Quản lý Docker Compose bằng Portainer: YAML lên stack thật

P P T P Chung

Quản lý Docker Compose bằng Portainer: từ file YAML đến stack chạy thật

Docker Compose giúp mô tả nhiều container bằng một file YAML duy nhất. Portainer giúp biến file đó thành stack dễ triển khai, dễ quan sát, dễ vận hành qua giao diện web. Kết hợp cả hai → quy trình triển khai gọn hơn: viết cấu hình một lần, deploy nhanh, theo dõi trực quan, rollback/sửa lỗi dễ hơn.

Nếu bạn từng chạy:

docker compose up -d

rồi phải SSH vào server, xem log thủ công, sửa file, restart service… thì Portainer là lớp quản lý đáng dùng. Nó không thay thế Docker Compose; nó “đóng gói” trải nghiệm vận hành Compose thành UI có kiểm soát.

Bài này đi từ file YAML đến stack chạy thật: cấu trúc Compose, cách import vào Portainer, quản lý biến môi trường, volume, network, log, update, lỗi hay gặp.


Portainer quản lý Docker Compose như thế nào?

Trong Portainer, Stack thường tương ứng với một dự án Docker Compose. Bạn đưa vào một file docker-compose.yml, Portainer dùng Docker API để tạo:

Services/containersNetworksVolumesEnvironment variablesPort mappingsRestart policies

Nói ngắn: YAML → Portainer Stack → Docker resources.

Ví dụ Compose tối giản:

services:
  app:
    image: nginx:alpine
    ports:
      - "8080:80"
    restart: unless-stopped

Khi deploy qua Portainer, bạn sẽ thấy container app, port 8080, log, trạng thái, nút restart/recreate, stats CPU/RAM.


Khi nào nên dùng Portainer thay vì CLI?

CLI vẫn mạnh. Nhưng Portainer hữu ích khi:

– Có nhiều stack trên một hoặc nhiều server. – Team cần xem trạng thái mà không cần SSH. – Muốn deploy từ Git repo. – Muốn quản lý secret/env/volume/network trực quan. – Cần phân quyền người dùng. – Muốn thao tác nhanh: restart container, xem log, exec shell, update image.

CLI phù hợp automation sâu. Portainer phù hợp vận hành hằng ngày.

Mô hình thực tế hay dùng:

– Dev viết docker-compose.yml. – Git lưu version. – Portainer kéo file từ Git. – Ops/admin deploy/update qua UI. – Log/health/resource xem ngay trong Portainer.


Chuẩn bị file Docker Compose tốt trước khi đưa vào Portainer

Portainer chỉ deploy tốt nếu YAML rõ ràng. File Compose nên có cấu trúc ổn định.

Ví dụ stack web + database:

services:
  web:
    image: nginx:alpine
    container_name: demo_web
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      - db
    restart: unless-stopped
    networks:
      - app_net

db: image: postgres:16-alpine container_name: demo_db environment: POSTGRES_DB: appdb POSTGRES_USER: appuser POSTGRES_PASSWORD: change_me volumes: - db_data:/var/lib/postgresql/data restart: unless-stopped networks: - app_net

volumes: db_data:

networks: app_net: driver: bridge

Điểm cần chú ý:

Không hardcode mật khẩu trong YAML

Không nên để:

POSTGRES_PASSWORD: super_secret_password

Tốt hơn: dùng biến môi trường.

environment:
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

Trong Portainer, bạn khai báo env khi deploy stack.

Dùng named volume cho dữ liệu quan trọng

Nên dùng:

volumes:
  db_data:

Tránh lưu DB vào thư mục tạm không rõ vị trí. Named volume → dễ backup, dễ quản lý hơn.

Đặt restart policy

Production nên có:

restart: unless-stopped

Container lỗi/reboot server → tự khởi động lại.

Tránh dùng container_name nếu cần scale

container_name tiện nhìn tên, nhưng gây xung đột khi scale nhiều replica. Với app cần scale, bỏ container_name.

Cài Portainer nhanh

Nếu chưa có Portainer, có thể chạy bằng Docker:

docker volume create portainer_data
docker run -d 
  -p 8000:8000 
  -p 9443:9443 
  --name portainer 
  --restart=always 
  -v /var/run/docker.sock:/var/run/docker.sock 
  -v portainer_data:/data 
  portainer/portainer-ce:latest

Truy cập:

https://SERVER_IP:9443

Tạo admin user → chọn local Docker environment.

Lưu ý bảo mật: mount /var/run/docker.sock cho Portainer nghĩa là Portainer có quyền rất mạnh trên Docker host. Chỉ cấp quyền admin cho người tin cậy, bật HTTPS, dùng mật khẩu mạnh, hạn chế public UI nếu có thể.


Deploy stack từ file YAML trong Portainer

Trong Portainer:

1. Vào Stacks. 2. Chọn Add stack. 3. Đặt tên stack, ví dụ: demo. 4. Chọn phương thức: – Web editor: dán YAML trực tiếp. – Upload: upload file Compose. – Git repository: kéo từ repo. 5. Nhập biến môi trường nếu YAML dùng ${VAR}. 6. Bấm Deploy the stack.

Sau vài giây, Portainer tạo container, network, volume. Vào stack → thấy danh sách service/container. Nếu lỗi, xem phần deployment error/log.


Deploy từ Git: cách phù hợp cho team

Deploy bằng Web editor nhanh, nhưng khó quản lý version. Với team hoặc production, nên dùng Git.

Cấu trúc repo ví dụ:

my-stack/
├── docker-compose.yml
├── .env.example
└── README.md

Trong Portainer → StacksAdd stackRepository:

– Repository URL: URL Git. – Compose path: docker-compose.yml. – Branch: main hoặc prod. – Authentication: nếu repo private. – Environment variables: khai báo trực tiếp trong Portainer.

Ưu điểm:

– YAML có lịch sử thay đổi. – Review qua pull request. – Rollback bằng Git commit. – Portainer chỉ là nơi deploy.

Một số bản Portainer hỗ trợ webhook/update từ Git. Khi push code hoặc đổi image tag, bạn có thể trigger redeploy.


Quản lý biến môi trường trong Portainer

Compose thường dùng:

services:
  app:
    image: myapp:${APP_VERSION}
    environment:
      DATABASE_URL: ${DATABASE_URL}
      NODE_ENV: production

Trong Portainer Stack, mục Environment variables khai báo:

APP_VERSION=1.2.3
DATABASE_URL=postgres://user:pass@db:5432/app

Gợi ý:

– Không commit file .env chứa secret. – Commit .env.example để mô tả biến cần có. – Tách biến theo môi trường: dev/staging/prod. – Dùng image tag rõ, tránh latest trong production.

Không nên:

image: myapp:latest

Nên:

image: myapp:1.2.3

latest → khó biết đang chạy version nào, rollback khó.


Theo dõi stack đang chạy

Sau deploy, Portainer giúp xem nhanh:

Logs

Vào container → Logs. Dùng để kiểm tra app boot lỗi, DB connection, migration, crash loop.

Lỗi thường gặp:

connection refused

Nguyên nhân thường: app chạy trước DB, sai hostname, DB chưa ready. Trong Compose, service name là DNS nội bộ. Nếu service DB tên db, app nên kết nối host db, không phải localhost.

Console

Portainer cho mở shell:

/bin/sh

hoặc:

/bin/bash

Hữu ích để kiểm tra file, env, network:

env
ping db
curl http://web

Stats

Xem CPU/RAM/network. Nếu container dùng RAM tăng liên tục → có thể memory leak. Nếu restart liên tục → xem log + healthcheck.


Healthcheck: nhỏ nhưng rất đáng có

Thêm healthcheck giúp biết container “sống thật” hay chỉ “process còn chạy”.

Ví dụ PostgreSQL:

services:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
      interval: 10s
      timeout: 5s
      retries: 5

Với web app:

healthcheck:
  test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
  interval: 30s
  timeout: 5s
  retries: 3

Portainer sẽ hiển thị trạng thái health nếu Docker nhận được.


Update stack an toàn

Khi cần update image/version:

1. Sửa tag image trong YAML hoặc biến APP_VERSION. 2. Redeploy stack trong Portainer. 3. Kiểm tra log. 4. Kiểm tra health/status. 5. Test endpoint chính.

Ví dụ đổi:

image: myapp:1.2.3

thành:

image: myapp:1.2.4

Nếu dùng Git → commit → Portainer pull/redeploy.

Lưu ý: nếu image tag giữ nguyên nhưng image mới được push lại, cần bật pull image khi redeploy hoặc dùng tag bất biến tốt hơn.


Backup volume trước thay đổi lớn

Stack mất có thể tạo lại. Dữ liệu trong volume mới quan trọng.

Ví dụ backup PostgreSQL đúng cách:

docker exec demo_db pg_dump -U appuser appdb > backup.sql

Hoặc backup volume ở mức filesystem tùy tình huống. Trước migration DB, upgrade major version, đổi volume mapping → backup bắt buộc.

Không nên xóa stack kèm volume nếu chưa chắc. Trong Portainer, thao tác remove stack có thể ảnh hưởng resource liên quan. Đọc kỹ tùy chọn trước khi xác nhận.


Lỗi hay gặp khi deploy Compose bằng Portainer

Port đã được dùng

Lỗi dạng:

Bind for 0.0.0.0:8080 failed: port is already allocated

Fix: đổi port host:

ports:
  - "8081:80"

hoặc dừng container đang chiếm port.

File path tương đối không như mong đợi

Compose CLI chạy từ thư mục chứa file. Portainer lưu stack ở path riêng. Bind mount kiểu:

volumes:
  - ./data:/data

có thể không trỏ tới nơi bạn nghĩ. Production nên dùng absolute path hoặc named volume:

volumes:
  - /opt/myapp/data:/data

hoặc:

volumes:
  - app_data:/data

App không kết nối DB

Sai:

localhost:5432

Đúng trong network Compose:

db:5432
localhost trong container là chính container đó, không phải host, không phải DB container.

Biến môi trường trống

YAML dùng:

${DATABASE_URL}

nhưng Portainer chưa khai báo → app lỗi. Fix: thêm env trong Stack hoặc dùng default:

DATABASE_URL: ${DATABASE_URL:-postgres://appuser:pass@db:5432/appdb}

Best practices thực tế

Một stack một mục đích rõ: app + DB + cache liên quan. – Dùng Git cho production. – Không dùng latest cho image production. – Khai báo restart policy. – Dùng named volume cho dữ liệu. – Thêm healthcheck cho service quan trọng. – Không hardcode secret trong YAML. – Backup trước update lớn. – Theo dõi log sau mỗi redeploy. – Ghi README deploy/runbook ngay trong repo.

Một stack tốt không chỉ “chạy được”, mà còn dễ hiểu, dễ cập nhật, dễ khôi phục khi lỗi.


Kết luận thực tế

Docker Compose là ngôn ngữ mô tả hạ tầng container đơn giản, còn Portainer là bảng điều khiển giúp biến mô tả đó thành hệ thống đang chạy. Từ một file YAML, bạn có thể tạo stack, quản lý container, xem log, chỉnh env, update image, kiểm tra volume/network mà không cần thao tác CLI liên tục.

Cách làm bền vững: viết Compose rõ ràng, lưu Git, dùng biến môi trường, tránh hardcode secret, đặt image tag cụ thể, backup dữ liệu, theo dõi log sau deploy. Portainer không làm hệ thống tự động tốt lên nếu YAML lộn xộn; nhưng với cấu hình chuẩn, nó giúp vận hành Docker Compose nhanh, minh bạch, ít lỗi hơn.

YAML tốt → stack ổn. Git rõ → update an toàn. Portainer → vận hành nhẹ hơn.

Tác giả

P T P

Chia sẻ

Bài viết liên quan

Bình luận (0)

Email của bạn sẽ không được hiển thị công khai.

Chưa có bình luận. Hãy là người đầu tiên!