Sổ tay Docker: Cách sử dụng Docker Compose
Trong phần trước, bạn đã học cách chạy ứng dụng trên nhiều container trong Docker. Bạn cũng đã tìm hiểu về biến môi trường và volume được đặt tên trong Docker. Nếu bỏ lỡ thì bạn có thể xem lại bài viết này ở dưới đây:
Qua hướng dẫn đó, bạn đã biết được những khó khăn khi quản lý một dự án nhiều container. Thay vì viết nhiều lệnh như vậy, có một cách dễ dàng hơn để quản lý các dự án nhiều container, đó là sử dụng Docker Compose.
Theo tài liệu Docker –
Docker Compose là một công cụ để định nghĩa và chạy các ứng dụng trên nhiều Docker Container. Với Docker Compose, bạn sử dụng tệp YAML để cấu hình các dịch vụ của ứng dụng. Sau đó, với một lệnh duy nhất, bạn tạo và khởi động tất cả các dịch vụ từ cấu hình của mình.
Mặc dù Docker Compose hoạt động trong mọi môi trường, nhưng nó tập trung hơn vào việc phát triển và thử nghiệm. Việc sử dụng Docker Compose trên môi trường sản xuất (production) hoàn toàn không được khuyến khích.
Kiến thức cơ bản về Docker Compose
Truy cập thư mục mà bạn đã clone từ repository https://github.com/fhsinchy/docker-handbook-projects. Vào bên trong thư mục notes-api/api
và tạo một tệp Dockerfile.dev
. Đặt mã sau vào đó:
# stage one
FROM node:lts-alpine as builder
# install dependencies for node-gyp
RUN apk add --no-cache python make g++
WORKDIR /app
COPY ./package.json .
RUN npm install
# stage two
FROM node:lts-alpine
ENV NODE_ENV=development
USER node
RUN mkdir -p /home/node/app
WORKDIR /home/node/app
COPY . .
COPY --from=builder /app/node_modules /home/node/app/node_modules
CMD [ "./node_modules/.bin/nodemon", "--config", "nodemon.json", "bin/www" ]
Mã gần như giống với mã Dockerfile
mà bạn đã làm việc với trong phần trước. Ba điểm khác biệt trong tệp này như sau:
- Trên dòng 10, chúng tôi chạy lệnh
npm install
thay vìnpm run install --only=prod
vì chúng tôi cũng muốn các phụ thuộc cho môi trường development. - Trên dòng 15, chúng tôi đặt biến môi trường
NODE_ENV
thànhdevelopment
thay vìproduction
. - Ở dòng 24, chúng tôi sử dụng một công cụ có tên là nodemon để có được tính năng tải lại nóng cho API.
Bạn đã biết rằng dự án này có hai container:
notes-db
– Một máy chủ cơ sở dữ liệu được cung cấp bởi PostgreSQL.notes-api
– REST API được cung cấp bởi Express.js.
Trong thế giới của Docker Compose, mỗi container tạo nên ứng dụng được gọi là một dịch vụ. Bước đầu tiên khi tạo một dự án nhiều container là định nghĩa các dịch vụ này.
Cũng giống như Docker daemon sử dụng Dockerfile
để xây dựng image, Docker Compose sử dụng một tệp docker-compose.yaml
để đọc các định nghĩa dịch vụ từ đó.
Đi tới thư mục notes-api
và tạo một tệp docker-compose.yaml
mới . Đặt mã sau vào tệp mới tạo:
version: "3.8"
services:
db:
image: postgres:12
container_name: notes-db-dev
volumes:
- notes-db-dev-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: notesdb
POSTGRES_PASSWORD: secret
api:
build:
context: ./api
dockerfile: Dockerfile.dev
image: notes-api:dev
container_name: notes-api-dev
environment:
DB_HOST: db ## same as the database service name
DB_DATABASE: notesdb
DB_PASSWORD: secret
volumes:
- /home/node/app/node_modules
- ./api:/home/node/app
ports:
- 3000:3000
volumes:
notes-db-dev-data:
name: notes-db-dev-data
Mọi tệp docker-compose.yaml
hợp lệ bắt đầu bằng cách chỉ định phiên bản tệp. Tại thời điểm viết bài, 3.8
là phiên bản mới nhất. Bạn có thể tra cứu phiên bản mới nhất tại đây.
Các khối trong tệp YAML được định nghĩa bằng cách thụt lề. Tôi sẽ đi qua từng khối và sẽ giải thích những gì chúng làm.
- Khối
services
chứa các định nghĩa cho mỗi dịch vụ hoặc container trong ứng dụng.db
vàapi
là hai dịch vụ trong dự án này. - Khối
db
định nghĩa một dịch vụ mới trong ứng dụng và lưu giữ thông tin cần thiết để khởi động container. Mọi dịch vụ đều yêu cầu image được tạo sẵn hoặcDockerfile
để chạy một container. Đối với dịch vụdb
, chúng tôi đang sử dụng image PostgreSQL chính thức. - Không giống như dịch vụ
db
, image được tạo sẵn cho dịch vụapi
không tồn tại. Vì vậy, chúng tôi sẽ sử dụng tệpDockerfile.dev
. - Khối
volumes
định nghĩa tên volume cần thiết cho các dịch vụ. Nó tạo volumenotes-db-dev-data
được sử dụng bởi dịch vụdb
.
Bây giờ đã có tổng quan cấp cao về tệp docker-compose.yaml
, chúng ta hãy xem xét kỹ hơn các dịch vụ riêng lẻ.
Mã định nghĩa cho dịch vụ db
như sau:
db:
image: postgres:12
container_name: notes-db-dev
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: notesdb
POSTGRES_PASSWORD: secret
- Chỉ dẫn
image
chỉ định image và thẻ sử dụng cho container này. Chúng tôi đang sử dụng imagepostgres:12
để chạy container cơ sở dữ liệu. - Chỉ dẫn
container_name
chỉ định tên của container. Theo mặc định các container được đặt tên theo cú pháp<project directory name>_<service name>
. Bạn có thể ghi đè điều đó bằng cách sử dụngcontainer_name
. - Chỉ dẫn
volumes
lưu giữ ánh xạ ổ đĩa cho các dịch vụ và hỗ trợ volume được đặt tên, volume ản danh và liên kết ràng buộc. Cú pháp<source>:<destination>
giống với những gì bạn đã thấy trước đây. - Chỉ dẫn
environment
lưu giữ các giá trị của các biến môi trường khác nhau cần thiết cho dịch vụ.
Mã định nghĩa cho dịch vụ api
như sau:
api:
build:
context: ./api
dockerfile: Dockerfile.dev
image: notes-api:dev
container_name: notes-api-dev
environment:
DB_HOST: db ## same as the database service name
DB_DATABASE: notesdb
DB_PASSWORD: secret
volumes:
- /home/node/app/node_modules
- ./api:/home/node/app
ports:
- 3000:3000
- Dịch vụ
api
không đi kèm với một image được xây dựng trước. Thay vào đó, nó có một cấu hình xây dựng. Dưới khốibuild
, chúng ta xác định ngữ cảnh và tên của Dockerfile để xây dựng một khối. Bây giờ bạn đã hiểu về ngữ cảnh và Dockerfile nên tôi sẽ không dành thời gian giải thích những điều đó. - Chỉ dẫn
image
chỉ định tên của image được xây dựng. Nếu không được gán, image sẽ được đặt tên theo cú pháp<project directory name>_<service name>
. - Bên trong chỉ dẫn
environment
, biếnDB_HOST
thể hiện một tính năng của Docker Compose. Nghĩa là, bạn có thể tham chiếu đến một dịch vụ khác trong cùng một ứng dụng bằng cách sử dụng tên của nó. Vì vậy,db
ở đây, sẽ được thay thế bằng địa chỉ IP trong container dịch vụapi
. Các biếnDB_DATABASE
vàDB_PASSWORD
phải khớp vớiPOSTGRES_DB
vàPOSTGRES_PASSWORD
tương ứng được định nghĩa ở dịch vụdb
. - Trong khối
volumes
, bạn có thể thấy một volume ẩn danh và một liên kết ràng buộc được mô tả. Cú pháp giống với những gì bạn đã thấy trong các phần trước. - Chỉ dẫn
ports
xác định bất kỳ ánh xạ cổng. Cú pháp,<host port>:<container port>
giống với tùy chọn--publish
bạn đã sử dụng trước đây.
Cuối cùng, mã định nghĩa cho volumes
như sau:
volumes:
notes-db-dev-data:
name: notes-db-dev-data
Bất kỳ volume được đặt tên nào được sử dụng trong bất kỳ dịch vụ nào phải được định nghĩa ở đây. Nếu bạn không xác định tên, tập sẽ được đặt tên theo cú pháp <project directory name>_<volume key>
và tên ở đây là notes-db-dev-data
.
Bạn có thể tìm hiểu về các tùy chọn khác nhau cho cấu hình volume trong tài liệu chính thức.
Cách chạy dịch vụ trong Docker Compose
Có một số cách chạy các dịch vụ được định nghĩa trong tệp YAML. Lệnh đầu tiên mà bạn sẽ học là lệnh up
. Lệnh up
xây dựng bất kỳ image nào bị thiếu, tạo container, và chạy tất cả chúng.
Tuy nhiên, trước khi thực hiện lệnh, hãy đảm bảo rằng bạn đã mở terminal của mình trong cùng một thư mục chứa tệp docker-compose.yaml
. Điều này rất quan trọng đối với mọi lệnh docker-compose
bạn thực hiện.
docker-compose --file docker-compose.yaml up --detach
# Creating network "notes-api_default" with the default driver
# Creating volume "notes-db-dev-data" with default driver
# Building api
# Sending build context to Docker daemon 37.38kB
#
# Step 1/13 : FROM node:lts-alpine as builder
# ---> 471e8b4eb0b2
# Step 2/13 : RUN apk add --no-cache python make g++
# ---> Running in 197056ec1964
### LONG INSTALLATION STUFF GOES HERE ###
# Removing intermediate container 197056ec1964
# ---> 6609935fe50b
# Step 3/13 : WORKDIR /app
# ---> Running in 17010f65c5e7
# Removing intermediate container 17010f65c5e7
# ---> b10d12e676ad
# Step 4/13 : COPY ./package.json .
# ---> 600d31d9362e
# Step 5/13 : RUN npm install
# ---> Running in a14afc8c0743
### LONG INSTALLATION STUFF GOES HERE ###
# Removing intermediate container a14afc8c0743
# ---> 952d5d86e361
# Step 6/13 : FROM node:lts-alpine
# ---> 471e8b4eb0b2
# Step 7/13 : ENV NODE_ENV=development
# ---> Running in 0d5376a9e78a
# Removing intermediate container 0d5376a9e78a
# ---> 910c081ce5f5
# Step 8/13 : USER node
# ---> Running in cfaefceb1eff
# Removing intermediate container cfaefceb1eff
# ---> 1480176a1058
# Step 9/13 : RUN mkdir -p /home/node/app
# ---> Running in 3ae30e6fb8b8
# Removing intermediate container 3ae30e6fb8b8
# ---> c391cee4b92c
# Step 10/13 : WORKDIR /home/node/app
# ---> Running in 6aa27f6b50c1
# Removing intermediate container 6aa27f6b50c1
# ---> 761a7435dbca
# Step 11/13 : COPY . .
# ---> b5d5c5bdf3a6
# Step 12/13 : COPY --from=builder /app/node_modules /home/node/app/node_modules
# ---> 9e1a19960420
# Step 13/13 : CMD [ "./node_modules/.bin/nodemon", "--config", "nodemon.json", "bin/www" ]
# ---> Running in 5bdd62236994
# Removing intermediate container 5bdd62236994
# ---> 548e178f1386
# Successfully built 548e178f1386
# Successfully tagged notes-api:dev
# Creating notes-api-dev ... done
# Creating notes-db-dev ... done
Tùy chọn --detach
hoặc -d
ở đây có chức năng giống như bạn đã thấy trước đây. Tùy chọn --file
hoặc -f
chỉ cần thiết nếu file YAML không được đặt tên là docker-compose.yaml
(nhưng tôi đã sử dụng ở đây cho mục đích minh họa).
Ngoài lệnh up
còn có lệnh start
. Sự khác biệt chính giữa hai điều này là lệnh start
không tạo các container bị thiếu, chỉ chạy các container hiện có. Về cơ bản nó giống như lệnh container start
.
Tùy chọn --build
cho lệnh up
bắt buộc xây dựng lại các image. Có một số tùy chọn khác cho lệnh up
mà bạn có thể xem trong tài liệu chính thức.
Cách liệt kê các dịch vụ trong Docker Compose
Mặc dù các container dịch vụ được chạy bởi Docker Compose có thể được liệt kê bằng cách sử dụng lệnh container ls
, nhưng có lệnh ps
chỉ liệt kê các container được định nghĩa trong YAML.
docker-compose ps
# Name Command State Ports
# -------------------------------------------------------------------------------
# notes-api-dev docker-entrypoint.sh ./nod ... Up 0.0.0.0:3000->3000/tcp
# notes-db-dev docker-entrypoint.sh postgres Up 5432/tcp
Nó không nhiều thông tin như đầu ra của lệnh container ls
, nhưng nó hữu ích khi bạn có hàng tấn container chạy đồng thời.
Cách thực thi các lệnh bên trong một dịch vụ đang chạy trong Docker Compose
Tôi hy vọng bạn nhớ ở phần trước rằng bạn phải chạy một số tập lệnh để tạo các bảng cơ sở dữ liệu cho API này.
Cũng giống như lệnh container exec
, có một lệnh exec
cho docker-compose
. Cú pháp chung cho lệnh như sau:
docker-compose exec <service name> <command>
Để thực hiện lệnh npm run db:migrate
bên trong dịch vụ api
, bạn có thể thực hiện lệnh sau:
docker-compose exec api npm run db:migrate
# > notes-api@ db:migrate /home/node/app
# > knex migrate:latest
#
# Using environment: development
# Batch 1 run: 1 migrations
Không giống như lệnh container exec
, bạn không cần phải truyền cờ -it
cho các phiên tương tác. docker-compose
làm điều đó tự động.
Cách truy cập log từ một dịch vụ đang chạy trong Docker Compose
Bạn cũng có thể sử dụng lệnh logs
để truy cập log từ một dịch vụ đang chạy. Cú pháp chung cho lệnh như sau:
docker-compose logs <service name>
Để truy cập nhật ký từ dịch vụ api
, hãy thực hiện lệnh sau:
docker-compose logs api
# Attaching to notes-api-dev
# notes-api-dev | [nodemon] 2.0.7
# notes-api-dev | [nodemon] reading config ./nodemon.json
# notes-api-dev | [nodemon] to restart at any time, enter `rs`
# notes-api-dev | [nodemon] or send SIGHUP to 1 to restart
# notes-api-dev | [nodemon] ignoring: *.test.js
# notes-api-dev | [nodemon] watching path(s): *.*
# notes-api-dev | [nodemon] watching extensions: js,mjs,json
# notes-api-dev | [nodemon] starting `node bin/www`
# notes-api-dev | [nodemon] forking
# notes-api-dev | [nodemon] child pid: 19
# notes-api-dev | [nodemon] watching 18 files
# notes-api-dev | app running -> http://127.0.0.1:3000
Đây chỉ là một phần từ đầu ra log. Bạn có thể tham gia vào luồng đầu ra của dịch vụ và nhận log thời gian thực bằng cách sử dụng tùy chọn -f
hoặc --follow
. Bất kỳ log nào sau đó sẽ hiển thị ngay lập tức trong terminal miễn là bạn không thoát ra bằng cách nhấn ctrl + c
hoặc đóng cửa sổ. Container sẽ tiếp tục chạy ngay cả khi bạn thoát ra khỏi cửa sổ log.
Cách dừng các dịch vụ trong Docker Compose
Để dừng dịch vụ, có hai cách tiếp cận mà bạn có thể thực hiện. Đầu tiên là lệnh down
. Lệnh down
dừng tất cả các container chạy và xóa chúng khỏi hệ thống. Nó cũng xóa bất kỳ mạng nào:
docker-compose down --volumes
# Stopping notes-api-dev ... done
# Stopping notes-db-dev ... done
# Removing notes-api-dev ... done
# Removing notes-db-dev ... done
# Removing network notes-api_default
# Removing volume notes-db-dev-data
Tùy chọn --volumes
chỉ ra rằng bạn muốn xóa bất kỳ volume được đặt tên nào được định nghĩa trong khối volumes
. Bạn có thể tìm hiểu về các tùy chọn bổ sung cho lệnh down
trong tài liệu chính thức.
Một lệnh khác để dừng các dịch vụ là lệnh stop
có chức năng giống với lệnh container stop
. Nó dừng tất cả các container cho ứng dụng và giữ chúng. Những container này sau đó có thể được khởi động bằng lệnh start
hoặc up
.
Cách tạo một ứng dụng Full-stack trong Docker Compose
Trong phần phụ này, chúng tôi sẽ thêm giao diện người dùng cho Notes API của mình và biến nó thành một ứng dụng hoàn chỉnh. Tôi sẽ không giải thích bất kỳ tệp Dockerfile.dev
nào trong phần này (ngoại trừ tệp cho dịch vụ nginx
) vì chúng giống với một số tệp khác mà bạn đã thấy trong các phần trước.
Nếu bạn đã nhân bản kho lưu trữ mã dự án, thì hãy vào bên trong thư mục fullstack-notes-application
. Mỗi thư mục bên trong thư mục gốc của dự án chứa mã cho từng dịch vụ và Dockerfile
.
Trước khi chúng ta bắt đầu với tệp docker-compose.yaml
, hãy xem một sơ đồ về cách thức ứng dụng sẽ làm việc:
Thay vì chấp nhận các yêu cầu trực tiếp như chúng ta đã làm trước đây, trong ứng dụng này, tất cả các yêu cầu sẽ được nhận trước bởi một dịch vụ NGINX (hãy gọi nó là bộ định tuyến – router).
Sau đó, bộ định tuyến sẽ xem liệu điểm cuối được yêu cầu có thông tin /api
ở trong đó hay không. Nếu có, router sẽ định tuyến yêu cầu đến back-end hoặc nếu không, router sẽ định tuyến yêu cầu đến front-end.
Bạn làm điều này vì khi bạn chạy một ứng dụng giao diện người dùng, nó không chạy bên trong container. Nó chạy trên trình duyệt, được phân phối từ một container. Do đó, mạng Compose không hoạt động như mong đợi và ứng dụng giao diện người dùng không tìm thấy dịch vụ api
.
Mặt khác, NGINX chạy bên trong một container và có thể giao tiếp với các dịch vụ khác nhau trên toàn bộ ứng dụng.
Tôi sẽ không đi sâu vào cấu hình của NGINX ở đây. Chủ đề đó nằm ngoài phạm vi của hướng dẫn này. Nhưng nếu bạn muốn xem nó, hãy tiếp tục và kiểm tra các tệp /notes-api/nginx/development.conf
và /notes-api/nginx/production.conf
. Mã cho /notes-api/nginx/Deockerfile.dev
như sau:
FROM nginx:stable-alpine
COPY ./development.conf /etc/nginx/conf.d/default.conf
Tất cả những gì nó làm là sao chép tệp cấu hình vào /etc/nginx/conf.d/default.conf
bên trong container.
Hãy cập nhật tệp docker-compose.yaml
. Ngoài các dịch vụ api
và db
sẽ có các dịch vụ client
và nginx
. Cũng sẽ có một số định nghĩa về mạng mà tôi sẽ trình bày ngay sau đây.
version: "3.8"
services:
db:
image: postgres:12
container_name: notes-db-dev
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_DB: notesdb
POSTGRES_PASSWORD: secret
networks:
- backend
api:
build:
context: ./api
dockerfile: Dockerfile.dev
image: notes-api:dev
container_name: notes-api-dev
volumes:
- /home/node/app/node_modules
- ./api:/home/node/app
environment:
DB_HOST: db ## same as the database service name
DB_PORT: 5432
DB_USER: postgres
DB_DATABASE: notesdb
DB_PASSWORD: secret
networks:
- backend
client:
build:
context: ./client
dockerfile: Dockerfile.dev
image: notes-client:dev
container_name: notes-client-dev
volumes:
- /home/node/app/node_modules
- ./client:/home/node/app
networks:
- frontend
nginx:
build:
context: ./nginx
dockerfile: Dockerfile.dev
image: notes-router:dev
container_name: notes-router-dev
restart: unless-stopped
ports:
- 8080:80
networks:
- backend
- frontend
volumes:
db-data:
name: notes-db-dev-data
networks:
frontend:
name: fullstack-notes-application-network-frontend
driver: bridge
backend:
name: fullstack-notes-application-network-backend
driver: bridge
Tệp gần như giống với tệp trước đó bạn đã làm việc. Điều duy nhất cần giải thích là cấu hình mạng. Mã cho khối networks
như sau:
networks:
frontend:
name: fullstack-notes-application-network-frontend
driver: bridge
backend:
name: fullstack-notes-application-network-backend
driver: bridge
Tôi đã định nghĩa hai mạng cầu nối. Theo mặc định, Compose tạo một mạng cầu nối và gắn tất cả các container vào đó. Tuy nhiên, trong dự án này, tôi muốn cách ly mạng. Vì vậy, tôi đã định nghĩa hai mạng, một cho các dịch vụ front-end và một cho các dịch vụ back-end.
Tôi cũng đã thêm khối networks
trong mỗi định nghĩa dịch vụ. Bằng cách này dịch vụ api
và dịch vụ db
sẽ được gắn vào một mạng và dịch vụ client
sẽ được gắn vào một mạng riêng biệt. Nhưng dịch vụ nginx
sẽ được gắn vào cả hai mạng để nó có thể hoạt động như một bộ định tuyến giữa các dịch vụ front-end và back-end.
Bắt đầu tất cả các dịch vụ bằng cách thực hiện lệnh sau:
docker-compose --file docker-compose.yaml up --detach
# Creating network "fullstack-notes-application-network-backend" with driver "bridge"
# Creating network "fullstack-notes-application-network-frontend" with driver "bridge"
# Creating volume "notes-db-dev-data" with default driver
# Building api
# Sending build context to Docker daemon 37.38kB
#
# Step 1/13 : FROM node:lts-alpine as builder
# ---> 471e8b4eb0b2
# Step 2/13 : RUN apk add --no-cache python make g++
# ---> Running in 8a4485388fd3
### LONG INSTALLATION STUFF GOES HERE ###
# Removing intermediate container 8a4485388fd3
# ---> 47fb1ab07cc0
# Step 3/13 : WORKDIR /app
# ---> Running in bc76cc41f1da
# Removing intermediate container bc76cc41f1da
# ---> 8c03fdb920f9
# Step 4/13 : COPY ./package.json .
# ---> a1d5715db999
# Step 5/13 : RUN npm install
# ---> Running in fabd33cc0986
### LONG INSTALLATION STUFF GOES HERE ###
# Removing intermediate container fabd33cc0986
# ---> e09913debbd1
# Step 6/13 : FROM node:lts-alpine
# ---> 471e8b4eb0b2
# Step 7/13 : ENV NODE_ENV=development
# ---> Using cache
# ---> b7c12361b3e5
# Step 8/13 : USER node
# ---> Using cache
# ---> f5ac66ca07a4
# Step 9/13 : RUN mkdir -p /home/node/app
# ---> Using cache
# ---> 60094b9a6183
# Step 10/13 : WORKDIR /home/node/app
# ---> Using cache
# ---> 316a252e6e3e
# Step 11/13 : COPY . .
# ---> Using cache
# ---> 3a083622b753
# Step 12/13 : COPY --from=builder /app/node_modules /home/node/app/node_modules
# ---> Using cache
# ---> 707979b3371c
# Step 13/13 : CMD [ "./node_modules/.bin/nodemon", "--config", "nodemon.json", "bin/www" ]
# ---> Using cache
# ---> f2da08a5f59b
# Successfully built f2da08a5f59b
# Successfully tagged notes-api:dev
# Building client
# Sending build context to Docker daemon 43.01kB
#
# Step 1/7 : FROM node:lts-alpine
# ---> 471e8b4eb0b2
# Step 2/7 : USER node
# ---> Using cache
# ---> 4be5fb31f862
# Step 3/7 : RUN mkdir -p /home/node/app
# ---> Using cache
# ---> 1fefc7412723
# Step 4/7 : WORKDIR /home/node/app
# ---> Using cache
# ---> d1470d878aa7
# Step 5/7 : COPY ./package.json .
# ---> Using cache
# ---> bbcc49475077
# Step 6/7 : RUN npm install
# ---> Using cache
# ---> 860a4a2af447
# Step 7/7 : CMD [ "npm", "run", "serve" ]
# ---> Using cache
# ---> 11db51d5bee7
# Successfully built 11db51d5bee7
# Successfully tagged notes-client:dev
# Building nginx
# Sending build context to Docker daemon 5.12kB
#
# Step 1/2 : FROM nginx:stable-alpine
# ---> f2343e2e2507
# Step 2/2 : COPY ./development.conf /etc/nginx/conf.d/default.conf
# ---> Using cache
# ---> 02a55d005a98
# Successfully built 02a55d005a98
# Successfully tagged notes-router:dev
# Creating notes-client-dev ... done
# Creating notes-api-dev ... done
# Creating notes-router-dev ... done
# Creating notes-db-dev ... done
Bây giờ hãy truy cập http://localhost:8080
và xem kết quả.
Hãy thử thêm và xóa các ghi chú để xem ứng dụng có hoạt động bình thường hay không. Dự án cũng đi kèm với các tập lệnh shell và Makefile
. Khám phá chúng để xem cách bạn có thể chạy dự án này mà không cần sự trợ giúp của docker-compose
như bạn đã làm trong phần trước.
Bài viết này được dịch từ cuốn sách The Docker Handbook của Farhan Hasin Chowdhury: