Sổ tay Docker: Cách chạy ứng dụng JavaScript trên nhiều Container

Trong phần trước, bạn đã tìm hiểu các thao tác Docker Network cơ bản như tạo và xóa mạng, cách gắn container vào mạng, cách tách container ra khỏi mạng. Nếu bỏ lỡ thì bạn có thể xem lại bài viết này ở dưới đây:

Sổ tay Docker: Thao tác Docker Network cơ bản
Bạn sẽ tìm hiểu các kiến thức cơ bản về Docker Network, các thao tác mạng cơ bản như: tạo và xóa mạng, gắn container vào mạng, gỡ container khỏi mạng.

Bây giờ bạn đã tìm hiểu đầy đủ về mạng trong Docker, trong phần này, bạn sẽ học cách chứa một dự án đa vùng chứa chính thức. Dự án bạn sẽ làm việc là một dự án notes-api đơn giản được cung cấp bởi Express.js và PostgreSQL.

Trong dự án này có tổng cộng hai container mà bạn sẽ phải kết nối bằng mạng. Ngoài ra, bạn cũng sẽ tìm hiểu về các khái niệm như biến môi trường và volume (ổ đĩa) được đặt tên. Không cần phải nói nhiều nữa, chúng ta hãy bắt đầu ngay.

Cách chạy máy chủ cơ sở dữ liệu

Máy chủ cơ sở dữ liệu trong dự án này là một máy chủ PostgreSQL đơn giản và sử dụng image Postgres chính thức .

Theo tài liệu chính thức, để chạy container cho image này, bạn phải cung cấp biến môi trường POSTGRES_PASSWORD. Ngoài cái này, tôi cũng sẽ cung cấp tên cho cơ sở dữ liệu mặc định bằng cách sử dụng biến môi trường POSTGRES_DB. PostgreSQL mặc định lắng nghe trên cổng 5432, vì vậy bạn cũng cần phải xuất bản nó.

Để chạy máy chủ cơ sở dữ liệu, bạn có thể thực hiện lệnh sau:

docker container run \
    --detach \
    --name=notes-db \
    --env POSTGRES_DB=notesdb \
    --env POSTGRES_PASSWORD=secret \
    --network=notes-api-network \
    postgres:12

# a7b287d34d96c8e81a63949c57b83d7c1d71b5660c87f5172f074bd1606196dc

docker container ls

# CONTAINER ID   IMAGE         COMMAND                  CREATED              STATUS              PORTS      NAMES
# a7b287d34d96   postgres:12   "docker-entrypoint.s…"   About a minute ago   Up About a minute   5432/tcp   notes-db

Các tùy chọn --env cho lệnh container runcontainer create có thể được sử dụng để cung cấp các biến môi trường cho container. Như bạn có thể thấy, container cơ sở dữ liệu đã được tạo thành công và hiện đang chạy.

Mặc dù container đang chạy nhưng có một vấn đề nhỏ. Các cơ sở dữ liệu như PostgreSQL, MongoDB và MySQL duy trì dữ liệu của chúng trong một thư mục. PostgreSQL sử dụng thư mục /var/lib/postgresql/data bên trong container để lưu giữ dữ liệu.

Bây giờ điều gì sẽ xảy ra nếu container bị xóa vì một lý do nào đó? Bạn sẽ mất tất cả dữ liệu của mình. Để giải quyết vấn đề này, có thể sử dụng volume.

Cách làm việc với volume trong Docker

Trước đây, bạn đã làm việc với các liên kết ràng buộc (bind mount) và volume ẩn danh. Một volume được đặt tên rất giống với một volume ẩn danh ngoại trừ việc bạn có thể tham chiếu tới một volume được đặt tên bằng cách sử dụng tên của nó.

Volume cũng là một đối tượng logic trong Docker và có thể được điều khiển bằng dòng lệnh. Lệnh volume create có thể được sử dụng để tạo ra một volume được đặt tên.

Cú pháp chung cho lệnh như sau:

docker volume create <volume name>

Để tạo một volume được đặt tên, notes-db-databạn có thể thực hiện lệnh sau:

docker volume create notes-db-data

# notes-db-data

docker volume ls

# DRIVER    VOLUME NAME
# local     notes-db-data

Volume này hiện đã có thể gắn vào /var/lib/postgresql/data bên trong container notes-db. Để làm như vậy, hãy dừng và xóa container notes-db:

docker container stop notes-db

# notes-db

docker container rm notes-db

# notes-db

Bây giờ, hãy chạy một container mới và chỉ định volume bằng cách sử dụng tùy chọn --volume hoặc -v.

docker container run \
    --detach \
    --volume notes-db-data:/var/lib/postgresql/data \
    --name=notes-db \
    --env POSTGRES_DB=notesdb \
    --env POSTGRES_PASSWORD=secret \
    --network=notes-api-network \
    postgres:12

# 37755e86d62794ed3e67c19d0cd1eba431e26ab56099b92a3456908c1d346791

Bây giờ hãy kiểm tra container notes-db để đảm bảo rằng quá trình gắn kết đã thành công:

docker container inspect --format='{{range .Mounts}} {{ .Name }} {{end}}' notes-db

#  notes-db-data

Bây giờ dữ liệu sẽ được lưu trữ an toàn bên trong volume notes-db-data và có thể được sử dụng lại trong tương lai. Một liên kết ràng buộc cũng có thể được sử dụng thay cho một volume được đặt tên ở đây, nhưng tôi thích một volume được đặt tên trong các trường hợp như vậy.

Cách truy cập log từ container trong Docker

Để xem log từ một container, bạn có thể sử dụng lệnh container logs. Cú pháp chung cho lệnh như sau:

docker container logs <container identifier>

Để truy cập nhật ký từ container notes-db, bạn có thể thực hiện lệnh sau:

docker container logs notes-db

# The files belonging to this database system will be owned by user "postgres".
# This user must also own the server process.

# The database cluster will be initialized with locale "en_US.utf8".
# The default database encoding has accordingly been set to "UTF8".
# The default text search configuration will be set to "english".
#
# Data page checksums are disabled.
#
# fixing permissions on existing directory /var/lib/postgresql/data ... ok
# creating subdirectories ... ok
# selecting dynamic shared memory implementation ... posix
# selecting default max_connections ... 100
# selecting default shared_buffers ... 128MB
# selecting default time zone ... Etc/UTC
# creating configuration files ... ok
# running bootstrap script ... ok
# performing post-bootstrap initialization ... ok
# syncing data to disk ... ok
#
#
# Success. You can now start the database server using:
#
#     pg_ctl -D /var/lib/postgresql/data -l logfile start
#
# initdb: warning: enabling "trust" authentication for local connections
# You can change this by editing pg_hba.conf or using the option -A, or
# --auth-local and --auth-host, the next time you run initdb.
# waiting for server to start....2021-01-25 13:39:21.613 UTC [47] LOG:  starting PostgreSQL 12.5 (Debian 12.5-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
# 2021-01-25 13:39:21.621 UTC [47] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
# 2021-01-25 13:39:21.675 UTC [48] LOG:  database system was shut down at 2021-01-25 13:39:21 UTC
# 2021-01-25 13:39:21.685 UTC [47] LOG:  database system is ready to accept connections
#  done
# server started
# CREATE DATABASE
#
#
# /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
#
# 2021-01-25 13:39:22.008 UTC [47] LOG:  received fast shutdown request
# waiting for server to shut down....2021-01-25 13:39:22.015 UTC [47] LOG:  aborting any active transactions
# 2021-01-25 13:39:22.017 UTC [47] LOG:  background worker "logical replication launcher" (PID 54) exited with exit code 1
# 2021-01-25 13:39:22.017 UTC [49] LOG:  shutting down
# 2021-01-25 13:39:22.056 UTC [47] LOG:  database system is shut down
#  done
# server stopped
#
# PostgreSQL init process complete; ready for start up.
#
# 2021-01-25 13:39:22.135 UTC [1] LOG:  starting PostgreSQL 12.5 (Debian 12.5-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
# 2021-01-25 13:39:22.136 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
# 2021-01-25 13:39:22.136 UTC [1] LOG:  listening on IPv6 address "::", port 5432
# 2021-01-25 13:39:22.147 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
# 2021-01-25 13:39:22.177 UTC [75] LOG:  database system was shut down at 2021-01-25 13:39:22 UTC
# 2021-01-25 13:39:22.190 UTC [1] LOG:  database system is ready to accept connections

Rõ ràng là đoạn log ở dòng 57, cơ sở dữ liệu đã hoạt động và sẵn sàng chấp nhận các kết nối từ bên ngoài. Ngoài ra còn có tùy chọn --follow hoặc -f cho phép bạn đính kèm console vào đầu ra log để nhận một luồng log liên tục.

Cách tạo mạng và gắn máy chủ cơ sở dữ liệu trong Docker

Như bạn đã tìm hiểu trong phần trước, các container phải được gắn vào mạng cầu nối do người dùng xác định để giao tiếp với nhau bằng cách sử dụng tên container. Để làm như vậy, hãy tạo một mạng có tên notes-api-network trong hệ thống của bạn:

docker network create notes-api-network

Bây giờ đính kèm container notes-db vào mạng này bằng cách thực hiện lệnh sau:

docker network connect notes-api-network notes-db

Cách viết Dockerfile

Chuyển đến thư mục mà bạn đã clone từ repository https://github.com/fhsinchy/docker-handbook-projects. Bên trong đó, vào bên trong thư mục notes-api/api và tạo Dockerfile mới. Đặt mã sau vào file mới tạ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 --only=prod

# stage two
FROM node:lts-alpine

EXPOSE 3000
ENV NODE_ENV=production

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", "bin/www" ]

Đây là một bản dựng nhiều giai đoạn. Giai đoạn đầu tiên được sử dụng để xây dựng và cài đặt các phụ thuộc bằng cách sử dụng node-gyp và giai đoạn thứ hai là để chạy ứng dụng. Tôi sẽ đi qua các bước ngắn gọn:

  • Giai đoạn 1 sử dụng image node:lts-alpine làm image cơ sở và đặt tên tên giai đoạn 1 là builder.
  • Trên dòng 5, chúng ta cài đặt python, makeg++. Công cụ node-gyp yêu cầu ba gói này để chạy.
  • Trên dòng 7, chúng ta thiết lập thư mục làm việc WORKDIR/app.
  • Trên dòng 9 và 10, chúng ta sao chép tệp package.json vào WORKDIR và cài đặt tất cả các phần phụ thuộc.
  • Giai đoạn 2 cũng sử dụng image node:lts-alpine làm image cơ sở.
  • Trên dòng 16, chúng ta thiết lập biến môi trường NODE_ENVproduction. Đây là điều quan trọng để API chạy đúng cách.
  • Từ dòng 18 đến dòng 20, chúng ta thiết lập người dùng mặc định thành node, tạo thư mục /home/node/app và thiết lập nó là WORKDIR.
  • Trên dòng 22, chúng ta sao chép tất cả các tệp dự án và trên dòng 23, chúng tôi sao chép thư mục node_modules từ giai đoạn builder. Thư mục này chứa tất cả các phụ thuộc được xây dựng cần thiết để chạy ứng dụng.
  • Trên dòng 25, chúng ta thiết lập lệnh mặc định.

Để xây dựng một image từ file Dockerfile này, bạn có thể thực hiện lệnh sau:

docker image build --tag notes-api .

# Sending build context to Docker daemon  37.38kB
# Step 1/14 : FROM node:lts-alpine as builder
#  ---> 471e8b4eb0b2
# Step 2/14 : RUN apk add --no-cache python make g++
#  ---> Running in 5f20a0ecc04b
# fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/main/x86_64/APKINDEX.tar.gz
# fetch http://dl-cdn.alpinelinux.org/alpine/v3.11/community/x86_64/APKINDEX.tar.gz
# (1/21) Installing binutils (2.33.1-r0)
# (2/21) Installing gmp (6.1.2-r1)
# (3/21) Installing isl (0.18-r0)
# (4/21) Installing libgomp (9.3.0-r0)
# (5/21) Installing libatomic (9.3.0-r0)
# (6/21) Installing mpfr4 (4.0.2-r1)
# (7/21) Installing mpc1 (1.1.0-r1)
# (8/21) Installing gcc (9.3.0-r0)
# (9/21) Installing musl-dev (1.1.24-r3)
# (10/21) Installing libc-dev (0.7.2-r0)
# (11/21) Installing g++ (9.3.0-r0)
# (12/21) Installing make (4.2.1-r2)
# (13/21) Installing libbz2 (1.0.8-r1)
# (14/21) Installing expat (2.2.9-r1)
# (15/21) Installing libffi (3.2.1-r6)
# (16/21) Installing gdbm (1.13-r1)
# (17/21) Installing ncurses-terminfo-base (6.1_p20200118-r4)
# (18/21) Installing ncurses-libs (6.1_p20200118-r4)
# (19/21) Installing readline (8.0.1-r0)
# (20/21) Installing sqlite-libs (3.30.1-r2)
# (21/21) Installing python2 (2.7.18-r0)
# Executing busybox-1.31.1-r9.trigger
# OK: 212 MiB in 37 packages
# Removing intermediate container 5f20a0ecc04b
#  ---> 637ca797d709
# Step 3/14 : WORKDIR /app
#  ---> Running in 846361b57599
# Removing intermediate container 846361b57599
#  ---> 3d58a482896e
# Step 4/14 : COPY ./package.json .
#  ---> 11b387794039
# Step 5/14 : RUN npm install --only=prod
#  ---> Running in 2e27e33f935d
#  added 269 packages from 220 contributors and audited 1137 packages in 140.322s
#
# 4 packages are looking for funding
#   run `npm fund` for details
#
# found 0 vulnerabilities
#
# Removing intermediate container 2e27e33f935d
#  ---> eb7cb2cb0b20
# Step 6/14 : FROM node:lts-alpine
#  ---> 471e8b4eb0b2
# Step 7/14 : EXPOSE 3000
#  ---> Running in 4ea24f871747
# Removing intermediate container 4ea24f871747
#  ---> 1f0206f2f050
# Step 8/14 : ENV NODE_ENV=production
#  ---> Running in 5d40d6ac3b7e
# Removing intermediate container 5d40d6ac3b7e
#  ---> 31f62da17929
# Step 9/14 : USER node
#  ---> Running in 0963e1fb19a0
# Removing intermediate container 0963e1fb19a0
#  ---> 0f4045152b1c
# Step 10/14 : RUN mkdir -p /home/node/app
#  ---> Running in 0ac591b3adbd
# Removing intermediate container 0ac591b3adbd
#  ---> 5908373dfc75
# Step 11/14 : WORKDIR /home/node/app
#  ---> Running in 55253b62ff57
# Removing intermediate container 55253b62ff57
#  ---> 2883cdb7c77a
# Step 12/14 : COPY . .
#  ---> 8e60893a7142
# Step 13/14 : COPY --from=builder /app/node_modules  /home/node/app/node_modules
#  ---> 27a85faa4342
# Step 14/14 : CMD [ "node", "bin/www" ]
#  ---> Running in 349c8ca6dd3e
# Removing intermediate container 349c8ca6dd3e
#  ---> 9ea100571585
# Successfully built 9ea100571585
# Successfully tagged notes-api:latest

Trước khi bạn chạy một container bằng image này, hãy đảm bảo rằng container cơ sở dữ liệu đang chạy và được đính kèm với notes-api-network.

docker container inspect notes-db

# [
#     {
#         ...
#         "State": {
#             "Status": "running",
#             "Running": true,
#             "Paused": false,
#             "Restarting": false,
#             "OOMKilled": false,
#             "Dead": false,
#             "Pid": 11521,
#             "ExitCode": 0,
#             "Error": "",
#             "StartedAt": "2021-01-26T06:55:44.928510218Z",
#             "FinishedAt": "2021-01-25T14:19:31.316854657Z"
#         },
#         ...
#         "Mounts": [
#             {
#                 "Type": "volume",
#                 "Name": "notes-db-data",
#                 "Source": "/var/lib/docker/volumes/notes-db-data/_data",
#                 "Destination": "/var/lib/postgresql/data",
#                 "Driver": "local",
#                 "Mode": "z",
#                 "RW": true,
#                 "Propagation": ""
#             }
#         ],
#         ...
#         "NetworkSettings": {
#             ...
#             "Networks": {
#                 "bridge": {
#                     "IPAMConfig": null,
#                     "Links": null,
#                     "Aliases": null,
#                     "NetworkID": "e4c7ce50a5a2a49672155ff498597db336ecc2e3bbb6ee8baeebcf9fcfa0e1ab",
#                     "EndpointID": "2a2587f8285fa020878dd38bdc630cdfca0d769f76fc143d1b554237ce907371",
#                     "Gateway": "172.17.0.1",
#                     "IPAddress": "172.17.0.2",
#                     "IPPrefixLen": 16,
#                     "IPv6Gateway": "",
#                     "GlobalIPv6Address": "",
#                     "GlobalIPv6PrefixLen": 0,
#                     "MacAddress": "02:42:ac:11:00:02",
#                     "DriverOpts": null
#                 },
#                 "notes-api-network": {
#                     "IPAMConfig": {},
#                     "Links": null,
#                     "Aliases": [
#                         "37755e86d627"
#                     ],
#                     "NetworkID": "06579ad9f93d59fc3866ac628ed258dfac2ed7bc1a9cd6fe6e67220b15d203ea",
#                     "EndpointID": "5b8f8718ec9a5ec53e7a13cce3cb540fdf3556fb34242362a8da4cc08d37223c",
#                     "Gateway": "172.18.0.1",
#                     "IPAddress": "172.18.0.2",
#                     "IPPrefixLen": 16,
#                     "IPv6Gateway": "",
#                     "GlobalIPv6Address": "",
#                     "GlobalIPv6PrefixLen": 0,
#                     "MacAddress": "02:42:ac:12:00:02",
#                     "DriverOpts": {}
#                 }
#             }
#         }
#     }
# ]

Tôi đã rút ngắn đầu ra để dễ xem ở đây. Trên hệ thống của tôi, container notes-db đang chạy, sử dụng volume notes-db-data và được gắn vào mạng notes-api-network.

Khi bạn đã chắc chắn rằng mọi thứ đã sẵn sàng, bạn có thể chạy một container mới bằng cách thực hiện lệnh sau:

docker container run \
    --detach \
    --name=notes-api \
    --env DB_HOST=notes-db \
    --env DB_DATABASE=notesdb \
    --env DB_PASSWORD=secret \
    --publish=3000:3000 \
    --network=notes-api-network \
    notes-api
    
# f9ece420872de99a060b954e3c236cbb1e23d468feffa7fed1e06985d99fb919

Bạn sẽ có thể tự mình hiểu được lệnh dài này, vì vậy tôi sẽ đi qua các biến môi trường một cách ngắn gọn.

Ứng dụng notes-api đòi hỏi ba biến môi trường được thiết lập. Chúng như sau:

  • DB_HOST - Đây là máy chủ cơ sở dữ liệu. Giả sử rằng cả máy chủ cơ sở dữ liệu và API đều được gắn vào cùng một mạng cầu nối do người dùng xác định, máy chủ cơ sở dữ liệu có thể được tham chiếu để sử dụng tên container của nó là notes-db trong trường hợp này.
  • DB_DATABASE - Cơ sở dữ liệu mà API này sẽ sử dụng. Khi chạy máy chủ cơ sở dữ liệu, chúng tôi đặt tên cơ sở dữ liệu mặc định là notesdb bằng cách sử dụng biến môi trường POSTGRES_DB. Chúng tôi sẽ sử dụng nó ở đây.
  • DB_PASSWORD - Mật khẩu để kết nối với cơ sở dữ liệu. Điều này cũng được thiết lập khi chạy máy chủ cơ sở dữ liệu bằng cách sử dụng biến môi trường POSTGRES_PASSWORD.

Để kiểm tra xem container có chạy đúng hay không, bạn có thể sử dụng lệnh container ls:

docker container ls

# CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS          PORTS                    NAMES
# f9ece420872d   notes-api     "docker-entrypoint.s…"   12 minutes ago   Up 12 minutes   0.0.0.0:3000->3000/tcp   notes-api
# 37755e86d627   postgres:12   "docker-entrypoint.s…"   17 hours ago     Up 14 minutes   5432/tcp                 notes-db

Container đang chạy. Bạn có thể truy cập http://127.0.0.1:3000/ để xem API đang hoạt động.

JavaScript application

Mặc dù container đang chạy, có một điều cuối cùng mà bạn sẽ phải làm trước khi có thể bắt đầu sử dụng nó. Bạn sẽ phải tạo dữ liệu cần thiết để thiết lập các bảng cơ sở dữ liệu và bạn có thể làm điều đó bằng cách thực hiện lệnh npm run db:migrate bên trong container.

Cách thực thi lệnh trong container đang chạy

Bạn đã học về cách thực thi các lệnh trong container đã dừng. Một kịch bản khác là thực thi một lệnh bên trong một container đang chạy.

Để thực hiện điều này, bạn sẽ phải sử dụng lệnhexec để thực hiện một lệnh tùy chỉnh bên trong một container đang chạy.

Cú pháp chung cho lệnh exec như sau:

docker container exec <container identifier> <command>

Để thực thi npm run db:migrate bên trong container notes-api, bạn có thể thực hiện lệnh sau:

docker container exec notes-api npm run db:migrate

# > notes-api@ db:migrate /home/node/app
# > knex migrate:latest
#
# Using environment: production
# Batch 1 run: 1 migrations

Trong trường hợp bạn muốn chạy một lệnh tương tác bên trong một container đang chạy, bạn sẽ phải sử dụng cờ -it. Ví dụ: nếu bạn muốn truy cập shell đang chạy bên trong container notes-api, bạn có thể thực hiện lệnh sau:

docker container exec -it notes-api sh

# / # uname -a
# Linux b5b1367d6b31 5.10.9-201.fc33.x86_64 #1 SMP Wed Jan 20 16:56:23 UTC 2021 x86_64 Linux

Cách viết tập lệnh quản lý trong Docker

Quản lý một dự án nhiều container cùng với mạng và volume có nghĩa là viết rất nhiều lệnh. Để đơn giản hóa quy trình, tôi thường nhờ sự trợ giúp từ các tập lệnh shell đơn giản và Makefile.

Bạn sẽ tìm thấy bốn tập lệnh shell trong thư mục notes-api. Chúng như sau:

  • boot.sh - Được sử dụng để khởi động các container nếu chúng đã tồn tại.
  • build.sh - Tạo và chạy các container. Nó cũng tạo ra image, volume và mạng nếu cần thiết.
  • destroy.sh - Loại bỏ tất cả các container, volume và mạng được liên kết với dự án này.
  • stop.sh - Dừng tất cả các container đang chạy.

Ngoài ra còn có một Makefile mà có bốn mục tiêu được đặt tên start, stop, builddestroy, mỗi cách gọi các kịch bản shell đề cập ở trên.

Nếu container ở trạng thái đang chạy trong hệ thống của bạn, việc thực thi make stop sẽ dừng tất cả các container. Việc thực thi make destroy sẽ dừng các container và xóa mọi thứ. Đảm bảo rằng bạn đang chạy các tập lệnh bên trong thư mục notes-api:

make destroy

# ./shutdown.sh
# stopping api container --->
# notes-api
# api container stopped --->

# stopping db container --->
# notes-db
# db container stopped --->

# shutdown script finished

# ./destroy.sh
# removing api container --->
# notes-api
# api container removed --->

# removing db container --->
# notes-db
# db container removed --->

# removing db data volume --->
# notes-db-data
# db data volume removed --->

# removing network --->
# notes-api-network
# network removed --->

# destroy script finished

Nếu bạn nhận được lỗi bị từ chối quyền, bạn nên thực thi lệnh chmod +x trên các tập lệnh:

chmod +x boot.sh build.sh destroy.sh shutdown.sh

Tôi sẽ không giải thích các tập lệnh này vì chúng là các câu lệnh if-else đơn giản cùng với một số lệnh Docker mà bạn đã thấy nhiều lần. Nếu bạn có một số hiểu biết về Linux shell, bạn cũng có thể hiểu các tập lệnh.

Trong hướng dẫn tiếp theo, bạn sẽ học cách sử dụng Docker Compose để chạy và quản lý các dịch vụ phức tạp.

Sổ tay Docker: Cách sử dụng Docker Composer
Trong hướng dẫn này, bạn sẽ tìm hiểu các kiến thức cơ bản về Docker Compose, cách chạy và quản lý các dịch vụ sử dụng Docker Compose.

Bài viết này được dịch từ cuốn sách The Docker Handbook của Farhan Hasin Chowdhury:

The Docker Handbook – 2021 Edition
The concept of containerization itself is pretty old. But the emergence of the Docker Engine [https://docs.docker.com/get-started/overview/#docker-engine] in2013 has made it much easier to containerize your applications. According to the Stack Overflow Developer Survey - 2020[https://insights.stackoverflow.com/survey/2020#overview…
DockerDevOpsLập Trình JavaScript
Bài Viết Liên Quan:
Deploy ứng dụng ASP.NET Core bằng Docker
Trung Nguyen 29/03/2021
Deploy ứng dụng ASP.NET Core bằng Docker

Bài viết này sẽ hướng dẫn bạn chi tiết cách deploy ứng dụng ASP.NET Core bằng Docker.

Sổ tay Docker: Cách sử dụng Docker Compose
Trung Nguyen 20/03/2021
Sổ tay Docker: Cách sử dụng Docker Compose

Trong hướng dẫn này, bạn sẽ tìm hiểu các kiến thức cơ bản về Docker Compose, cách chạy và quản lý các dịch vụ sử dụng Docker Compose.

Sổ tay Docker: Thao tác Docker Network cơ bản
Trung Nguyen 19/03/2021
Sổ tay Docker: Thao tác Docker Network cơ bản

Bạn sẽ tìm hiểu các kiến thức cơ bản về Docker Network, các thao tác mạng cơ bản như: tạo và xóa mạng, gắn container vào mạng, gỡ container khỏi mạng.

Sổ tay Docker: Cách xây dựng ứng dụng JavaScript với Docker
Trung Nguyen 19/03/2021
Sổ tay Docker: Cách xây dựng ứng dụng JavaScript với Docker

Trong hướng dẫn này, bạn sẽ học cách xây dựng ứng dụng JavaScript với Docker. Tạo image cho ứng dụng, tối ưu image, chạy container, ...