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 -drồ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/containers – Networks – Volumes – Environment variables – Port mappings – Restart 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-stoppedKhi 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_passwordTố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-stoppedContainer 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:latestTruy cập:
https://SERVER_IP:9443Tạ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.mdTrong Portainer → Stacks → Add stack → Repository:
– 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: productionTrong Portainer Stack, mục Environment variables khai báo:
APP_VERSION=1.2.3
DATABASE_URL=postgres://user:pass@db:5432/appGợ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:latestNên:
image: myapp:1.2.3Vì 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 refusedNguyê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/shhoặc:
/bin/bashHữu ích để kiểm tra file, env, network:
env
ping db
curl http://webStats
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: 5Với web app:
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3Portainer 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.3thành:
image: myapp:1.2.4Nế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.sqlHoặ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 allocatedFix: đổ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:/datacó 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:/datahoặc:
volumes:
- app_data:/dataApp không kết nối DB
Sai:
localhost:5432Đúng trong network Compose:
db:5432localhost 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.
Bình luận (0)
Chưa có bình luận. Hãy là người đầu tiên!