Docker là gì? Hướng dẫn sử dụng Docker trong Backend với Go
1. Docker là gì?
Docker là nền tảng hỗ trợ đóng gói và chạy ứng dụng trong các môi trường độc lập gọi là container. Thay vì chỉ chia sẻ mã nguồn, lập trình viên có thể mô tả môi trường chạy ứng dụng, các thư viện cần thiết và cách khởi động chương trình, sau đó đóng gói chúng thành Docker image để chạy trên những môi trường tương thích.
Trong phát triển Backend, Docker thường được sử dụng để chạy ứng dụng, database, cache và các dịch vụ phụ trợ mà không cần cài đặt thủ công từng thành phần trên máy tính của mỗi thành viên.
Những vấn đề Docker giải quyết
Giả sử một ứng dụng Backend được phát triển bằng Go và sử dụng PostgreSQL. Trên máy lập trình viên, ứng dụng có thể chạy bình thường, nhưng khi chuyển sang máy khác, chương trình lại gặp lỗi do khác phiên bản Go, thiếu thư viện hoặc cấu hình môi trường không giống nhau.
Docker giúp hạn chế những vấn đề này bằng cách mô tả môi trường chạy ứng dụng một cách nhất quán.
Một số lợi ích chính:
- Chuẩn hóa môi trường: Các thành viên có thể sử dụng cùng phiên bản image và cấu hình dịch vụ.
- Giảm phụ thuộc vào máy host: Không cần cài trực tiếp mọi dịch vụ như PostgreSQL hoặc Redis lên máy tính.
- Cô lập ứng dụng: Các container có môi trường thực thi và cấu hình riêng biệt.
- Dễ khởi tạo môi trường: Có thể tạo lại môi trường phát triển hoặc kiểm thử bằng các lệnh và tệp cấu hình.
- Hỗ trợ triển khai: Docker image có thể được chuyển đến môi trường khác để chạy mà không cần build lại từ mã nguồn tại đó.
Tuy nhiên, Docker không bảo đảm ứng dụng sẽ hoạt động giống hệt trên mọi hệ thống. Các yếu tố như kiến trúc CPU, biến môi trường, quyền truy cập, cấu hình mạng và tài nguyên vẫn có thể ảnh hưởng đến kết quả.
Vì sao môi trường chạy ứng dụng lại quan trọng?
Một ứng dụng không chỉ bao gồm mã nguồn. Để chạy được, nó còn cần runtime, thư viện, cấu hình và các dịch vụ phụ thuộc.
Ví dụ, một Go API có thể cần:
- Go toolchain để biên dịch ứng dụng hoặc một binary đã được biên dịch.
- PostgreSQL để lưu trữ dữ liệu.
- Redis để lưu cache.
- Các biến môi trường chứa thông tin cấu hình.
- Kết nối mạng giữa ứng dụng và các dịch vụ.
Nếu mỗi máy được thiết lập theo một cách khác nhau, việc tìm lỗi và tái tạo môi trường sẽ khó khăn hơn. Docker giúp mô tả và quản lý những thành phần này rõ ràng hơn.
2. Docker hoạt động như thế nào?
Containerization là gì?
Containerization là cách đóng gói ứng dụng cùng các thành phần cần thiết để chạy ứng dụng trong một môi trường được cô lập ở cấp hệ điều hành.
Trên Linux, container tận dụng các cơ chế của kernel như namespaces để cô lập những khía cạnh của tiến trình và cgroups để quản lý, giới hạn tài nguyên. Container không nhất thiết có một kernel riêng như máy ảo.
Docker cung cấp các công cụ để tạo image, khởi chạy container, quản lý mạng, lưu trữ và vòng đời của những container đó.
Docker Engine là gì?
Docker Engine là thành phần chịu trách nhiệm xây dựng và chạy container. Trong mô hình Docker Engine truyền thống, các thành phần chính gồm:
- Docker daemon (
dockerd): Quản lý image, container, network và volume. - Docker API: Cung cấp giao diện để các công cụ gửi yêu cầu quản lý Docker.
- Docker CLI (
docker): Công cụ dòng lệnh mà lập trình viên sử dụng để tương tác với Docker.
Ví dụ, khi chạy lệnh:
docker run nginx
Docker CLI gửi yêu cầu đến Docker Engine. Engine tìm image phù hợp, tải image nếu cần và tạo container để chạy chương trình.
Trên Windows và macOS, Docker Desktop thường sử dụng một môi trường Linux được quản lý bên dưới để chạy Linux container. Vì vậy, Linux container vẫn sử dụng kernel Linux trong môi trường đó, chứ không trực tiếp dùng kernel Windows hoặc macOS để chạy.
Container và hệ điều hành host
Container sử dụng tài nguyên của hệ thống bên dưới nhưng có môi trường thực thi được cô lập ở một mức độ nhất định.
Điều này giúp nhiều container chạy trên cùng một máy mà không cần tạo một hệ điều hành đầy đủ riêng cho từng container.
Ví dụ, một môi trường phát triển có thể chạy đồng thời:
- Container chứa Go API.
- Container chứa PostgreSQL.
- Container chứa Redis.
Mỗi container có vòng đời và cấu hình riêng. Chúng có thể giao tiếp với nhau thông qua Docker Network nếu được cấu hình phù hợp.
Phân biệt Docker với Virtual Machine
Docker Container thường chia sẻ kernel với hệ điều hành bên dưới. Vì không cần khởi chạy một hệ điều hành khách đầy đủ cho từng container, container thường nhẹ và khởi động nhanh hơn máy ảo.
Virtual Machine (VM) chạy một hệ điều hành khách riêng trên nền tảng ảo hóa. VM thường cần nhiều tài nguyên hơn container nhưng cung cấp ranh giới cô lập ở cấp máy ảo và cho phép chạy các hệ điều hành khách khác nhau, tùy hypervisor.
| Tiêu chí | Container | Virtual Machine |
|---|---|---|
| Kernel | Thường dùng chung kernel với môi trường bên dưới | Có hệ điều hành khách với kernel riêng |
| Thành phần đóng gói | Ứng dụng và các thành phần cần thiết | Hệ điều hành khách cùng ứng dụng |
| Tài nguyên | Thường nhẹ hơn | Thường cần nhiều tài nguyên hơn |
| Khởi động | Thường nhanh | Thường chậm hơn |
| Cách ly | Cách ly ở cấp tiến trình và tài nguyên | Cách ly ở cấp máy ảo |
Docker và VM không nhất thiết loại trừ nhau. Docker Desktop trên Windows hoặc macOS có thể chạy container Linux bên trong một máy ảo Linux được quản lý tự động.
3. Các thành phần cốt lõi của Docker
Để sử dụng Docker hiệu quả, cần phân biệt những thành phần sau.
Dockerfile
Dockerfile là tệp văn bản chứa các chỉ dẫn để xây dựng Docker image. Nó mô tả image nền, thư mục làm việc, tệp cần sao chép, các bước build và lệnh khởi động ứng dụng.
Docker Image
Docker image là mẫu đóng gói bất biến được sử dụng để tạo container. Image có thể chứa hệ thống tệp, binary ứng dụng, thư viện và metadata cần thiết để khởi chạy chương trình.
Một image có thể được sử dụng để tạo nhiều container.
Ví dụ:
docker pull postgres:17
Lệnh này tải image PostgreSQL có tag 17 từ registry mặc định.
Docker Container
Container là một thực thể được tạo từ image. Container có thể đang chạy, đã dừng hoặc ở một trạng thái khác trong vòng đời của nó.
Ví dụ:
docker run -d --name my-postgres postgres:17
Lệnh này tạo và khởi chạy một container PostgreSQL ở chế độ nền. Tuy nhiên, để sử dụng database ổn định, cần cấu hình thông tin khởi tạo, dữ liệu lưu trữ và kết nối phù hợp.
Docker Registry
Registry là nơi lưu trữ và phân phối Docker image. Docker Hub là một registry phổ biến; doanh nghiệp cũng có thể sử dụng registry riêng.
Quy trình thông thường là build image tại máy phát triển, đẩy image lên registry và tải image đó ở môi trường triển khai.
Docker Volume
Volume cung cấp cơ chế lưu trữ dữ liệu tách khỏi vòng đời của container. Đây là lựa chọn phổ biến để lưu dữ liệu PostgreSQL hoặc các dữ liệu cần tồn tại sau khi container bị xóa.
Nếu chỉ lưu dữ liệu bên trong lớp ghi của container, dữ liệu có thể mất khi container bị xóa.
Docker Network
Docker Network cho phép các container giao tiếp với nhau. Ví dụ, Go API có thể kết nối PostgreSQL bằng tên dịch vụ trong một Docker Compose network thay vì sử dụng địa chỉ IP cố định của container.
4. Các lệnh Docker cơ bản
Trước khi sử dụng Docker, cần cài đặt và khởi động Docker Engine hoặc Docker Desktop phù hợp với hệ điều hành.
docker pull
Tải image từ registry về máy.
docker pull postgres:17
docker images
Liệt kê những image đang có trên máy.
docker images
Lệnh này giúp kiểm tra image đã tải hoặc đã build trước đó.
docker build
Xây dựng image từ Dockerfile.
docker build -t my-go-app .
Trong đó:
-t my-go-app: đặt tên cho image..: chỉ định thư mục hiện tại làm build context.
Docker sử dụng Dockerfile cùng các tệp được phép truy cập trong build context để tạo image.
docker run
Tạo và khởi chạy container từ image.
docker run -d --name my-go-app -p 8080:8080 my-go-app
Trong đó:
-d: chạy container ở chế độ nền.--name: đặt tên container.-p 8080:8080: ánh xạ cổng 8080 trên máy host đến cổng 8080 trong container.
Lệnh này giả định ứng dụng bên trong container đang lắng nghe tại cổng 8080. Nếu chương trình sử dụng cổng khác hoặc chỉ lắng nghe trên 127.0.0.1, cần điều chỉnh cấu hình cho phù hợp.
docker ps
Liệt kê container đang chạy.
docker ps
Để xem cả những container đã dừng:
docker ps -a
docker logs
Xem log do container ghi ra standard output và standard error.
docker logs my-go-app
Theo dõi log liên tục:
docker logs -f my-go-app
Lệnh này hữu ích khi ứng dụng không khởi động được hoặc gặp lỗi trong quá trình xử lý request.
docker exec
Thực thi một lệnh bên trong container đang chạy.
docker exec -it my-go-app sh
Lệnh trên mở shell sh nếu image có cung cấp shell. Một số image tối giản không chứa shell, khi đó cần sử dụng phương pháp kiểm tra khác.
docker stop và docker rm
Dừng container:
docker stop my-go-app
Xóa container đã dừng:
docker rm my-go-app
Xóa container không đồng nghĩa với xóa image. Image vẫn có thể được sử dụng để tạo container mới.
5. Dockerfile là gì? Cách đóng gói ứng dụng Go
Dockerfile mô tả cách xây dựng image cho ứng dụng. Với Go, một quy trình phổ biến là biên dịch mã nguồn thành binary rồi chạy binary đó trong container.
Cấu trúc Dockerfile
Một số chỉ dẫn thường gặp:
FROM: chọn image nền.WORKDIR: đặt thư mục làm việc trong image.COPY: sao chép tệp từ build context vào image.RUN: thực thi lệnh trong quá trình build image.CMD: xác định lệnh mặc định khi container được khởi chạy.EXPOSE: khai báo cổng mà ứng dụng dự kiến sử dụng; không tự động công khai cổng ra máy host.
Ví dụ Dockerfile cho Go
Giả sử dự án có go.mod, go.sum và mã nguồn có thể build từ thư mục gốc. Có thể sử dụng Dockerfile đơn giản sau để minh họa:
FROM golang:1.25-alpine
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o server .
EXPOSE 8080
CMD ["./server"]
Giải thích:
FROM golang:1.25-alpinechọn image nền có Go.WORKDIR /appđặt thư mục làm việc.COPY go.mod go.sum ./sao chép tệp khai báo module.RUN go mod downloadtải các dependency.COPY . .sao chép mã nguồn vào image.RUN go build -o server .biên dịch chương trình thành binaryserver.EXPOSE 8080ghi nhận cổng dự kiến sử dụng.CMD ["./server"]chạy binary khi container khởi động.
Phiên bản Go trong image cần phù hợp với phiên bản mà dự án yêu cầu. Nếu dự án có cấu trúc thư mục khác, chẳng hạn mã nguồn nằm trong cmd/api, cần điều chỉnh đường dẫn build tương ứng.
Nên tạo tệp .dockerignore để loại trừ những tệp không cần đưa vào build context:
.git
.env
tmp/
bin/
Tệp .dockerignore giúp giảm kích thước build context và tránh đưa những tệp không cần thiết vào quá trình build. Không nên sao chép tệp chứa secret vào image.
Build image và chạy container
Tại thư mục chứa Dockerfile, chạy:
docker build -t my-go-app .
Sau khi build thành công, khởi chạy container:
docker run --rm --name my-go-app -p 8080:8080 my-go-app
Nếu ứng dụng thực sự lắng nghe trên cổng 8080 và bind đến địa chỉ phù hợp, có thể truy cập ứng dụng thông qua http://localhost:8080.
Tùy chọn --rm yêu cầu Docker tự xóa container sau khi container kết thúc. Nó không xóa image.
Multi-stage build
Dockerfile ở trên dùng image Go làm nền cho cả quá trình build và chạy ứng dụng. Tuy nhiên, ứng dụng đã biên dịch thường không cần toàn bộ công cụ build để hoạt động.
Multi-stage build cho phép sử dụng một stage để biên dịch và một stage khác để chạy binary. Cách làm này có thể giảm kích thước image cuối cùng và hạn chế các công cụ không cần thiết trong môi trường chạy.
Ví dụ:
FROM golang:1.25-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server .
FROM scratch
WORKDIR /app
COPY --from=builder /app/server ./server
EXPOSE 8080
CMD ["./server"]
Trong ví dụ này:
- Stage
builderbiên dịch ứng dụng. - Stage
scratchtạo image cuối cùng tối giản. COPY --from=builderchỉ sao chép binary sang stage chạy.
Image scratch phù hợp với binary có thể chạy mà không cần các thư viện hệ thống bổ sung. Nếu ứng dụng cần chứng chỉ CA để gọi HTTPS, tệp timezone hoặc thư viện native, cần bổ sung những thành phần đó hoặc chọn image chạy phù hợp hơn, chẳng hạn Alpine hoặc distroless.
Với dự án thực tế, cần kiểm tra kỹ các dependency runtime trước khi sử dụng image tối giản.
6. Docker Volume và Docker Network
Lưu trữ dữ liệu ngoài vòng đời container
Container có thể bị xóa và tạo lại trong quá trình phát triển hoặc triển khai. Vì vậy, dữ liệu cần giữ lại không nên chỉ được lưu trong lớp ghi của container.
Docker Volume cung cấp nơi lưu trữ độc lập với vòng đời container.
Ví dụ, tạo volume:
docker volume create postgres-data
Sau đó gắn volume vào thư mục dữ liệu của PostgreSQL:
docker run -d \
--name my-postgres \
-e POSTGRES_PASSWORD=change-me \
-v postgres-data:/var/lib/postgresql/data \
postgres:17
Trong ví dụ này, dữ liệu PostgreSQL được lưu trong volume postgres-data. Khi container bị xóa, volume vẫn tồn tại cho đến khi được xóa riêng.
change-me chỉ là mật khẩu minh họa, không nên dùng làm mật khẩu thực tế. Với môi trường thật, cần quản lý thông tin xác thực bằng cơ chế phù hợp.
Kết nối các container
Giả sử Go API và PostgreSQL chạy trong hai container riêng biệt. Chúng cần một mạng chung để giao tiếp.
Có thể tạo network:
docker network create backend-network
Sau đó khởi chạy PostgreSQL trên network đó:
docker run -d \
--name postgres-db \
--network backend-network \
-e POSTGRES_PASSWORD=change-me \
postgres:17
Container Go API có thể được kết nối vào cùng network. Khi cấu hình ứng dụng, có thể sử dụng hostname postgres-db để tìm dịch vụ PostgreSQL trong network này.
Đây chỉ là ví dụ minh họa kết nối mạng. Một ứng dụng thực tế còn cần cấu hình database name, username, password, cổng và cách khởi tạo dữ liệu phù hợp.
Kết nối ứng dụng Go với PostgreSQL
Trong Docker Compose, nếu dịch vụ database được khai báo là db, Go API thường kết nối đến PostgreSQL bằng hostname db và cổng mặc định 5432.
Ví dụ, cấu hình DSN trong môi trường phát triển có thể sử dụng:
postgres://app:password@db:5432/shop_db?sslmode=disable
Trong đó:
app: username của database.password: mật khẩu minh họa.db: tên dịch vụ PostgreSQL trong Compose network.5432: cổng PostgreSQL bên trong mạng container.shop_db: tên database.
Đây là chuỗi kết nối minh họa. Cấu hình TLS và thông tin xác thực cần được điều chỉnh theo môi trường thực tế.
Một lỗi phổ biến là dùng localhost từ bên trong container Go để kết nối PostgreSQL ở container khác. Trong trường hợp này, localhost trỏ về chính container Go, không phải container database. Vì vậy, cần sử dụng hostname dịch vụ hoặc địa chỉ phù hợp với mạng đã cấu hình.
7. Docker Compose là gì?
Docker Compose là công cụ giúp định nghĩa và quản lý nhiều dịch vụ Docker thông qua một tệp cấu hình, thường là compose.yaml.
Nếu không dùng Compose, lập trình viên phải tự tạo từng container, cấu hình network, volume, biến môi trường và các cổng kết nối. Khi có nhiều dịch vụ, việc quản lý thủ công trở nên khó khăn.
Compose cho phép mô tả những thành phần đó trong một tệp, sau đó khởi động hoặc dừng chúng bằng các lệnh thống nhất.
Cấu trúc tệp compose.yaml
Ví dụ, một dự án Backend cần PostgreSQL có thể sử dụng cấu hình sau:
services:
db:
image: postgres:17
environment:
POSTGRES_DB: shop_db
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
Giải thích:
services: khai báo các dịch vụ.db: tên dịch vụ PostgreSQL.image: image được sử dụng.environment: biến môi trường để khởi tạo database.ports: ánh xạ cổng giữa máy host và container.volumes: gắn volume để lưu dữ liệu.postgres-data: khai báo volume do Compose quản lý.
Trong ví dụ này, ${POSTGRES_PASSWORD} được lấy từ biến môi trường hoặc tệp .env theo cơ chế nội suy của Compose. Cần cung cấp giá trị trước khi khởi chạy. Không nên commit mật khẩu thật vào Git.
Khởi chạy Go API và PostgreSQL
Có thể mở rộng Compose để chạy cả Go API và PostgreSQL:
services:
api:
build: .
ports:
- "8080:8080"
environment:
DATABASE_URL: ${DATABASE_URL}
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
environment:
POSTGRES_DB: shop_db
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d shop_db"]
interval: 5s
timeout: 3s
retries: 5
volumes:
postgres-data:
Đây là cấu hình minh họa hoàn chỉnh về cấu trúc YAML, nhưng cần cung cấp đúng biến môi trường và bảo đảm ứng dụng Go đọc được DATABASE_URL.
Ví dụ, trong tệp .env dùng cho môi trường phát triển:
POSTGRES_PASSWORD=dev-password
DATABASE_URL=postgres://app:dev-password@db:5432/shop_db?sslmode=disable
Tệp .env này chỉ nhằm minh họa cách cấu hình cục bộ. Không sử dụng mật khẩu mẫu cho môi trường thật và không commit tệp chứa secret lên Git.
Trong cấu hình trên:
apiđược build từ Dockerfile trong thư mục hiện tại.dbsử dụng image PostgreSQL.DATABASE_URLtruyền chuỗi kết nối vào ứng dụng Go.healthcheckkiểm tra PostgreSQL đã sẵn sàng nhận kết nối hay chưa.depends_onvớicondition: service_healthyyêu cầu Compose chờ database đạt trạng thái healthy trước khi khởi động API.
depends_on không bảo đảm database sẽ luôn sẵn sàng trong toàn bộ vòng đời ứng dụng. API vẫn nên có cơ chế retry kết nối hoặc xử lý lỗi khi database tạm thời không truy cập được.
Nếu PostgreSQL đã được khởi tạo trước đó bằng volume, việc thay đổi POSTGRES_USER, POSTGRES_PASSWORD hoặc POSTGRES_DB không tự động thay đổi tài khoản và database đã tồn tại trong volume. Cần hiểu rõ cách image PostgreSQL khởi tạo dữ liệu lần đầu trước khi thay đổi cấu hình.
Quản lý vòng đời dịch vụ bằng Compose
Khởi động các dịch vụ:
docker compose up -d
Xem trạng thái:
docker compose ps
Theo dõi log:
docker compose logs -f
Dừng và xóa các container cùng network do Compose tạo:
docker compose down
Thông thường, lệnh docker compose down không xóa named volume trừ khi thêm tùy chọn -v. Điều này giúp dữ liệu database có thể được giữ lại giữa các lần khởi động.
Cần thận trọng khi sử dụng:
docker compose down -v
Thao tác này có thể xóa volume chứa dữ liệu mà bạn muốn giữ lại.
8. Docker trong quy trình phát triển Backend
Docker không chỉ dùng để chạy ứng dụng trên máy cá nhân. Nó còn hỗ trợ nhiều giai đoạn trong vòng đời phát triển phần mềm.
Môi trường development và testing
Thay vì yêu cầu mỗi thành viên tự cài PostgreSQL hoặc Redis, dự án có thể cung cấp tệp Compose để khởi tạo các dịch vụ phụ trợ với phiên bản và cấu hình thống nhất.
Điều này giúp thành viên mới bắt đầu làm việc dễ dàng hơn, đồng thời giảm những khác biệt giữa các môi trường phát triển.
Chạy database phục vụ Integration Testing
Integration Testing kiểm tra sự phối hợp giữa nhiều thành phần, chẳng hạn Repository, database và API.
Docker có thể được sử dụng để khởi chạy một PostgreSQL riêng phục vụ kiểm thử. Sau khi kiểm thử hoàn tất, môi trường có thể được dừng và tạo lại.
Cách này giúp kiểm thử trên database thật trong môi trường cô lập, thay vì phụ thuộc vào database cá nhân đang chứa dữ liệu phát triển.
Tuy nhiên, cần thiết kế quá trình khởi tạo schema, migration và dữ liệu kiểm thử rõ ràng. Không nên chạy kiểm thử phá hủy dữ liệu trên database production.
Chuẩn hóa môi trường giữa các thành viên
Khi dự án định nghĩa image và cấu hình dịch vụ rõ ràng, các thành viên có thể dùng cùng phiên bản PostgreSQL, Redis hoặc các dịch vụ liên quan.
Điều này không loại bỏ mọi khác biệt, nhưng giúp giảm những lỗi do cài đặt hoặc phiên bản môi trường không đồng nhất.
Đóng gói ứng dụng để triển khai
Một quy trình triển khai phổ biến có thể bao gồm:
- Lập trình viên thay đổi mã nguồn và commit lên Git.
- Hệ thống CI chạy kiểm thử và build Docker image.
- Image được đẩy lên registry.
- Môi trường triển khai tải image và khởi chạy container.
- Migration được chạy để cập nhật cấu trúc database nếu cần.
Đây là một quy trình minh họa; thứ tự thực tế phụ thuộc vào thiết kế CI/CD, cách quản lý migration và yêu cầu triển khai an toàn.
Cần phân biệt vai trò của các công cụ:
- Git quản lý mã nguồn và lịch sử thay đổi.
- Docker đóng gói và chạy ứng dụng trong container.
- Database Migration quản lý những thay đổi về cấu trúc database theo thời gian.
- CI/CD tự động hóa các bước build, kiểm thử và triển khai.
Các công cụ này bổ trợ cho nhau chứ không thay thế nhau.
9. Những lưu ý khi sử dụng Docker
Không nhúng mật khẩu và API key vào image
Không nên viết mật khẩu database, API key hoặc token thật trực tiếp trong Dockerfile hay đưa chúng vào image.
Thay vào đó, sử dụng biến môi trường hoặc cơ chế quản lý secret phù hợp với môi trường triển khai. Cũng cần tránh commit các tệp .env chứa thông tin nhạy cảm lên Git.
Quản lý dữ liệu bằng volume
Nếu database cần giữ dữ liệu sau khi container bị xóa, hãy cấu hình volume hoặc cơ chế lưu trữ bền vững phù hợp.
Đối với dữ liệu quan trọng, volume không thay thế cho backup và kế hoạch khôi phục dữ liệu.
Chọn phiên bản image phù hợp
Không nên mặc định sử dụng latest trong mọi môi trường, vì tag này có thể trỏ đến phiên bản khác tại những thời điểm khác nhau.
Nên chọn phiên bản phù hợp, kiểm thử trước khi nâng cấp và sử dụng quy trình quản lý image nhất quán. Trong các môi trường yêu cầu khả năng tái lập cao, có thể cân nhắc pin image bằng digest.
Health check và thứ tự khởi động dịch vụ
Việc một container đã được tạo hoặc tiến trình đã bắt đầu chạy không có nghĩa dịch vụ bên trong đã sẵn sàng nhận request.
Health check giúp kiểm tra trạng thái dịch vụ theo điều kiện cụ thể. Ứng dụng cũng nên xử lý tình huống dependency tạm thời chưa sẵn sàng, thay vì giả định mọi dịch vụ luôn hoạt động ngay khi container khởi động.
Giới hạn tài nguyên và bảo mật container
Container có thể tiêu thụ CPU, RAM và dung lượng đĩa đáng kể. Trong môi trường phù hợp, nên đặt giới hạn tài nguyên và theo dõi mức sử dụng để tránh ảnh hưởng đến những dịch vụ khác.
Ngoài ra, cần sử dụng image đáng tin cậy, cập nhật bản vá, hạn chế quyền không cần thiết và tránh chạy container với đặc quyền cao hơn mức cần thiết.
Docker hỗ trợ cô lập môi trường nhưng không tự động bảo đảm ứng dụng an toàn. Bảo mật vẫn phụ thuộc vào cấu hình, quyền truy cập và cách vận hành.
10. Kết luận
Docker là công cụ quan trọng trong phát triển Backend vì giúp đóng gói ứng dụng, chuẩn hóa môi trường và quản lý các dịch vụ phụ trợ một cách nhất quán.
Để sử dụng Docker hiệu quả, cần hiểu mối quan hệ giữa Dockerfile, image, container, volume, network và Docker Compose. Từ đó, có thể xây dựng môi trường phát triển với Go và PostgreSQL, chạy database phục vụ kiểm thử và đóng gói ứng dụng để triển khai.
Tuy nhiên, Docker không thay thế Git, Database Migration hay CI/CD. Mỗi công cụ giải quyết một phần khác nhau của quy trình phát triển phần mềm. Khi hiểu đúng vai trò của từng thành phần, lập trình viên có thể kết hợp chúng để xây dựng, kiểm thử và triển khai Backend dễ quản lý hơn.








Khoá học lập trình game con rắn cho trẻ em




