Docker là một công cụ mạnh mẽ giúp đơn giản hóa việc quản lý và vận hành các ứng dụng trong các container. Các container này cho phép chạy ứng dụng trong môi trường cách ly về tài nguyên, mang lại hiệu quả cao trong việc sử dụng hệ thống. Mặc dù tương tự như máy ảo, container lại có khả năng di động tốt hơn, tiết kiệm tài nguyên hơn và phụ thuộc ít vào hệ điều hành chủ.
Để tìm hiểu chi tiết hơn về các thành phần của Docker container, bạn có thể tham khảo bài viết Hệ Sinh Thái Docker: Giới Thiệu Các Thành Phần Phổ Biến.
Để triển khai Docker hiệu quả trên Ubuntu 22.04, việc chọn một VPS phù hợp là rất quan trọng. Với VPS giá rẻ tại DataOnline, bạn có thể dễ dàng thiết lập môi trường phát triển mạnh mẽ, tiết kiệm chi phí mà vẫn đảm bảo hiệu suất tối ưu cho dự án của mình.
DataOnline sẽ hướng dẫn bạn cách cài đặt Docker Community Edition (CE) trên Ubuntu 22.04, sử dụng Docker để làm việc với các container và image, cũng như cách đẩy một image lên Docker Repository để chia sẻ và triển khai ứng dụng.
Yêu Cầu
Để làm theo hướng dẫn này, bạn cần:
- Một máy chủ Ubuntu 22.04 được thiết lập theo hướng dẫn cài đặt ban đầu cho Ubuntu 22.04, bao gồm một người dùng không phải root với quyền sudo và có sẵn firewall.
- Một tài khoản trên Docker Hub nếu bạn muốn tạo image của riêng mình và đẩy chúng lên Docker Hub, như được trình bày trong các bước 7 và 8.
Bước 1 – Cài đặt Docker
Gói cài đặt Docker có sẵn trong kho chính thức của Ubuntu có thể không phải là phiên bản mới nhất. Để đảm bảo chúng ta nhận được phiên bản mới nhất, chúng ta sẽ cài đặt Docker từ kho chính thức của Docker. Để làm điều đó, chúng ta sẽ thêm nguồn gói mới, thêm GPG Key từ Docker để xác thực tính hợp lệ của các gói tải về, và sau đó cài đặt gói.
Cập nhật danh sách các gói đã có:
sudo apt update
Tiếp theo, cài đặt một vài gói cần thiết để apt có thể sử dụng các gói qua HTTPS:
sudo apt install apt-transport-https ca-certificates curl software-properties-common
Sau đó, thêm GPG Key cho kho Docker chính thức vào hệ thống của bạn:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
Thêm kho Docker vào nguồn APT:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Cập nhật lại danh sách các gói để hệ thống nhận diện được thay đổi:
sudo apt update
Kiểm tra xem bạn sắp cài đặt từ kho Docker hay không (thay vì kho mặc định của Ubuntu):
apt-cache policy docker-ce
Bạn sẽ thấy kết quả như sau (lưu ý số phiên bản Docker có thể khác):
Output of apt-cache policy docker-ce docker-ce: Installed: (none) Candidate: 5:20.10.14~3-0~ubuntu-jammy Version table: 5:20.10.14~3-0~ubuntu-jammy 500 500 https://download.docker.com/linux/ubuntu jammy/stable amd64 Packages 5:20.10.13~3-0~ubuntu-jammy 500 500 https://download.docker.com/linux/ubuntu jammy/stable amd64 Packages
Chú ý rằng docker-ce chưa được cài đặt, nhưng candidate để cài đặt là từ kho Docker cho Ubuntu 22.04 (jammy).
Cuối cùng, cài đặt Docker:
sudo apt install docker-ce
Docker bây giờ sẽ được cài đặt, daemon được khởi động, và quá trình sẽ được kích hoạt tự động khi khởi động hệ thống.
Kiểm tra trạng thái của Docker:
sudo systemctl status docker
Kết quả hiển thị nên tương tự như sau, cho thấy dịch vụ đang hoạt động:
Output ● docker.service - Docker Application Container Engine Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-04-01 21:30:25 UTC; 22s ago TriggeredBy: ● docker.socket Docs: https://docs.docker.com Main PID: 7854 (dockerd) Tasks: 7 Memory: 38.3M CPU: 340ms CGroup: /system.slice/docker.service └─7854 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Việc cài đặt Docker không chỉ mang lại cho bạn dịch vụ Docker (daemon) mà còn cung cấp tiện ích dòng lệnh docker, hay còn gọi là Docker client. Chúng ta sẽ khám phá cách sử dụng lệnh docker trong các bước sau.
Bước 2 – Thực thi lệnh Docker không cần Sudo
Theo mặc định, lệnh docker
chỉ có thể được chạy bởi người dùng root hoặc bởi một người dùng thuộc nhóm docker, nhóm này được tự động tạo ra trong quá trình cài đặt Docker. Nếu bạn cố gắng chạy lệnh docker mà không dùng sudo
hoặc không thuộc nhóm docker, bạn sẽ nhận được thông báo như sau:
Output docker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?. See 'docker run --help'.
Nếu bạn muốn tránh việc gõ sudo
mỗi khi chạy lệnh docker
, hãy thêm tên người dùng của bạn vào nhóm docker
:
sudo usermod -aG docker ${USER}
Để áp dụng thay đổi về thành viên nhóm, hãy đăng xuất khỏi máy chủ và đăng nhập lại, hoặc gõ:
su - ${USER}
Bạn sẽ được yêu cầu nhập mật khẩu của người dùng để tiếp tục.
Xác nhận rằng người dùng của bạn đã được thêm vào nhóm docker bằng cách gõ:
groups
Kết quả sẽ hiển thị ví dụ như:
Output sammy sudo docker
Nếu bạn cần thêm một người dùng khác vào nhóm docker mà bạn không đang đăng nhập, hãy chỉ định tên người dùng đó cụ thể:
sudo usermod -aG docker username
Phần còn lại của bài viết giả định rằng bạn đang chạy lệnh docker
với tư cách là một người dùng thuộc nhóm docker
. Nếu bạn không chọn cách này, hãy nhớ thêm sudo
trước các lệnh.
Chúng ta sẽ cùng khám phá lệnh docker
ngay tiếp theo.
Bước 3 – Sử dụng lệnh Docker
Lệnh docker được sử dụng bằng cách truyền vào chuỗi các tùy chọn và lệnh kèm theo các đối số. Cú pháp của lệnh như sau:
docker [option] [command] [arguments]
Để xem tất cả các lệnh con (subcommand) có sẵn, hãy gõ:
docker
Tính đến Docker phiên bản 20.10.14
, danh sách đầy đủ các lệnh con có sẵn bao gồm:
Output attach Attach local standard input, output, and error streams to a running container build Build an image from a Dockerfile commit Create a new image from a container's changes cp Copy files/folders between a container and the local filesystem create Create a new container diff Inspect changes to files or directories on a container's filesystem events Get real time events from the server exec Run a command in a running container export Export a container's filesystem as a tar archive history Show the history of an image images List images import Import the contents from a tarball to create a filesystem image info Display system-wide information inspect Return low-level information on Docker objects kill Kill one or more running containers load Load an image from a tar archive or STDIN login Log in to a Docker registry logout Log out from a Docker registry logs Fetch the logs of a container pause Pause all processes within one or more containers port List port mappings or a specific mapping for the container ps List containers pull Pull an image or a repository from a registry push Push an image or a repository to a registry rename Rename a container restart Restart one or more containers rm Remove one or more containers rmi Remove one or more images run Run a command in a new container save Save one or more images to a tar archive (streamed to STDOUT by default) search Search the Docker Hub for images start Start one or more stopped containers stats Display a live stream of container(s) resource usage statistics stop Stop one or more running containers tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE top Display the running processes of a container unpause Unpause all processes within one or more containers update Update configuration of one or more containers version Show the Docker version information wait Block until one or more containers stop, then print their exit codes
Để xem các tùy chọn của một lệnh cụ thể, hãy gõ:
docker docker-subcommand --help
Để xem thông tin hệ thống toàn cục về Docker, sử dụng:
docker info
Chúng ta sẽ cùng khám phá một số lệnh này. Bắt đầu bằng cách làm việc với các image.
Bước 4 – Làm việc với Docker Images
Các container Docker được xây dựng từ các image Docker. Theo mặc định, Docker tải các image này từ Docker Hub, một Docker registry do Docker, công ty đứng sau dự án Docker, quản lý.
Bất kỳ ai cũng có thể host các image Docker của họ trên Docker Hub, vì vậy hầu hết các ứng dụng và bản phân phối Linux mà bạn cần đều có image được host ở đó.
Để kiểm tra xem bạn có thể truy cập và tải image từ Docker Hub hay không, hãy gõ:
docker run hello-world
Kết quả sẽ cho biết Docker đang hoạt động đúng:
Output Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 2db29710123e: Pull complete Digest: sha256:bfea6278a0a267fad2634554f4f0c6f31981eea41c553fdf5a83e95a41d40c38 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. ...
Docker ban đầu không tìm thấy image hello-world
trên máy, nên nó tải image từ Docker Hub (repository mặc định). Sau khi image được tải xuống, Docker tạo ra một container từ image đó và ứng dụng bên trong container được thực thi, hiển thị thông báo.
Bạn có thể tìm kiếm các image có sẵn trên Docker Hub bằng cách sử dụng lệnh docker
với lệnh con search
. Ví dụ, để tìm kiếm image Ubuntu, hãy gõ:
docker search ubuntu
Lệnh này sẽ duyệt qua Docker Hub và trả về danh sách tất cả các image có tên khớp với chuỗi tìm kiếm. Kết quả sẽ tương tự như:
Output NAME DESCRIPTION STARS OFFICIAL AUTOMATED ubuntu Ubuntu is a Debian-based Linux operating sys… 14048 [OK] websphere-liberty WebSphere Liberty multi-architecture images … 283 [OK] ubuntu-upstart DEPRECATED, as is Upstart (find other proces… 112 [OK] neurodebian NeuroDebian provides neuroscience research s… 88 [OK] open-liberty Open Liberty multi-architecture images based… 51 [OK] ...
Trong cột OFFICIAL, “[OK]” cho biết image được xây dựng và hỗ trợ bởi công ty đứng sau dự án. Khi bạn đã xác định được image mà bạn muốn sử dụng, bạn có thể tải về máy tính của mình bằng lệnh con pull
.
Thực thi lệnh sau để tải image chính thức của ubuntu
về máy:
docker pull ubuntu
Bạn sẽ thấy kết quả như sau:
Output Using default tag: latest latest: Pulling from library/ubuntu e0b25ef51634: Pull complete Digest: sha256:9101220a875cee98b016668342c489ff0674f247f6ca20dfc91b91c0f28581ae Status: Downloaded newer image for ubuntu:latest docker.io/library/ubuntu:latest
Sau khi một image đã được tải về, bạn có thể chạy một container sử dụng image đã tải đó với lệnh run
. Như bạn đã thấy với ví dụ hello-world
, nếu image chưa được tải về khi lệnh docker
run
được thực thi, Docker client sẽ tải về image trước, sau đó chạy container sử dụng image đó.
Để xem các image đã được tải về trên máy của bạn, hãy gõ:
docker images
Kết quả sẽ hiển thị tương tự như sau:
Output REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 1d622ef86b13 3 weeks ago 73.9MB hello-world latest bf756fb1ae65 4 months ago 13.3kB
Như bạn sẽ thấy sau này trong hướng dẫn này, các image mà bạn dùng để chạy container có thể được chỉnh sửa và sử dụng để tạo ra các image mới, sau đó có thể được upload (đẩy – “push” là thuật ngữ kỹ thuật) lên Docker Hub hoặc các Docker registry khác.
Chúng ta hãy xem cách chạy container chi tiết hơn.
Bước 5 – Chạy một Docker Container
Container hello-world bạn chạy ở bước trước là một ví dụ về container chạy và thoát sau khi in ra một thông báo kiểm tra. Các container có thể hữu ích hơn thế nhiều và có thể chạy ở chế độ tương tác. Sau cùng, chúng tương tự như máy ảo, chỉ khác là tiết kiệm tài nguyên hơn.
Ví dụ, hãy chạy một container sử dụng image Ubuntu mới nhất. Sự kết hợp của tham số -i
và -t
sẽ cho phép bạn truy cập shell tương tác trong container:
docker run -it ubuntu
Dấu nhắc lệnh của bạn sẽ thay đổi để cho biết bạn đang làm việc bên trong container, và sẽ có dạng như sau:
Output root@d9b100f2f636:/#
Chú ý đến container id trong dấu nhắc lệnh. Trong ví dụ này, đó là d9b100f2f636
. Bạn sẽ cần container id này sau đó để nhận diện container khi muốn xóa nó.
Bây giờ, bạn có thể chạy bất kỳ lệnh nào bên trong container. Ví dụ, hãy cập nhật cơ sở dữ liệu gói bên trong container. Bạn không cần phải thêm sudo
vì bạn đang làm việc với tư cách root bên trong container:
apt update
Sau đó, cài đặt bất kỳ ứng dụng nào trong container. Ví dụ, cài đặt Node.js:
apt install nodejs
Lệnh trên cài đặt Node.js trong container từ kho chính thức của Ubuntu. Khi quá trình cài đặt hoàn tất, hãy xác nhận rằng Node.js đã được cài đặt bằng cách:
node -v
Bạn sẽ thấy phiên bản Node.js được hiển thị, ví dụ:
Output v12.22.9
Mọi thay đổi bạn thực hiện bên trong container chỉ áp dụng cho container đó.
Để thoát khỏi container, gõ exit
tại dấu nhắc lệnh.
Chúng ta sẽ cùng xem cách quản lý các container trên hệ thống của mình trong phần tiếp theo.
Bước 6 – Quản lý Docker Containers
Sau một thời gian sử dụng Docker, bạn sẽ có nhiều container đang chạy (active) và không chạy (inactive) trên máy của bạn. Để xem các container đang chạy, sử dụng:
docker ps
Bạn sẽ thấy kết quả tương tự như sau:
Output CONTAINER ID IMAGE COMMAND CREATED
Trong hướng dẫn này, bạn đã khởi động hai container; một từ image hello-world
và một từ image ubuntu
. Cả hai container hiện không còn chạy nữa, nhưng vẫn tồn tại trên hệ thống của bạn.
Để xem tất cả các container – cả đang chạy và đã dừng, chạy lệnh docker ps
với tham số -a
:
docker ps -a
Bạn sẽ thấy kết quả như sau:
Output CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c08a7a0d0e4 ubuntu "bash" About a minute ago Exited (0) 7 seconds ago dazzling_taussig 587000e49d53 hello-world "/hello" 5 minutes ago Exited (0) 5 minutes ago adoring_kowalevski
Để xem container mới nhất bạn tạo, sử dụng tham số -l
:
docker ps -l
Output CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c08a7a0d0e4 ubuntu "bash" 3 minutes ago Exited (0) 2 minutes ago dazzling_taussig
Để khởi động một container đã dừng, sử dụng lệnh docker start
kèm theo container ID hoặc tên container. Ví dụ, hãy khởi động container dựa trên Ubuntu có ID là 1c08a7a0d0e4:
docker start 1c08a7a0d0e4
Container sẽ được khởi động, và bạn có thể dùng lệnh docker ps
để xem trạng thái:
Output CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 1c08a7a0d0e4 ubuntu "bash" 6 minutes ago Up 8 seconds dazzling_taussig
Để dừng một container đang chạy, sử dụng lệnh docker stop
kèm theo container ID hoặc tên. Lần này, chúng ta sẽ dùng tên được Docker gán cho container, đó là dazzling_taussig
:
docker stop dazzling_taussig
Khi bạn quyết định rằng không còn cần container nữa, hãy xóa nó bằng lệnh docker rm
kèm theo container ID hoặc tên. Dùng lệnh docker ps -a
để tìm container của image hello-world và xóa nó:
docker rm adoring_kowalevski
Bạn có thể khởi động một container mới và đặt tên cho nó bằng cách sử dụng tham số --name
. Bạn cũng có thể sử dụng tham số --rm
để tạo một container tự xóa sau khi dừng. Xem lệnh docker run --help
để biết thêm thông tin về các tùy chọn này.
Các container có thể được chuyển thành image mà bạn có thể dùng để xây dựng container mới. Hãy cùng tìm hiểu cách thực hiện điều đó.
Bước 7 – Cam kết các thay đổi trong Container thành Docker Image
Khi bạn khởi chạy một image Docker, bạn có thể tạo mới, chỉnh sửa và xóa các tập tin như khi làm việc với máy ảo. Những thay đổi bạn thực hiện chỉ áp dụng cho container đó. Bạn có thể khởi động và dừng nó, nhưng khi bạn phá hủy container bằng lệnh docker rm
, các thay đổi sẽ bị mất vĩnh viễn.
Phần này sẽ hướng dẫn bạn cách lưu trạng thái của một container thành một Docker image mới.
Sau khi cài đặt Node.js bên trong container Ubuntu, bạn hiện có một container được khởi chạy từ một image, nhưng container này khác với image bạn đã dùng để tạo ra nó. Tuy nhiên, bạn có thể muốn sử dụng container Node.js này làm cơ sở cho các image mới sau này.
Sau đó, cam kết các thay đổi thành một Docker image mới bằng lệnh sau:
docker commit -m "What you did to the image" -a "Author Name" container_id repository/new_image_name
Tham số -m
dành cho thông điệp commit, giúp bạn và người khác biết những thay đổi bạn đã thực hiện. Tham số -a
được dùng để chỉ định tác giả.
container_id
là ID của container mà bạn đã lưu ý ở phần trước khi khởi chạy phiên Docker tương tác. Nếu bạn không tạo các repository riêng trên Docker Hub, repository thường là tên người dùng Docker Hub của bạn.
Ví dụ, với người dùng sammy, container ID là d9b100f2f636
, lệnh sẽ là:
docker commit -m "added Node.js" -a "sammy" d9b100f2f636 sammy/ubuntu-nodejs
Khi bạn commit một image, image mới sẽ được lưu trữ cục bộ trên máy tính của bạn. Sau đó trong hướng dẫn này, bạn sẽ học cách đẩy (push) image lên Docker registry như Docker Hub để người khác có thể truy cập.
Để xem lại danh sách các image, hãy dùng:
docker images
Bạn sẽ thấy kết quả như sau:
Output REPOSITORY TAG IMAGE ID CREATED SIZE sammy/ubuntu-nodejs latest 7c1f35226ca6 7 seconds ago 179MB ...
Trong ví dụ này, ubuntu-nodejs
là image mới, được tạo ra từ image ubuntu
có sẵn trên Docker Hub. Sự khác biệt về kích thước phản ánh những thay đổi đã được thực hiện (trong trường hợp này là cài đặt Node.js). Vì vậy, lần sau nếu bạn cần chạy container sử dụng Ubuntu với Node.js đã được cài sẵn, bạn chỉ cần dùng image mới này.
Bạn cũng có thể tạo image từ một Dockerfile
, cho phép tự động hóa quá trình cài đặt phần mềm trong một image mới. Tuy nhiên, điều đó vượt quá phạm vi của hướng dẫn này.
Bây giờ, hãy cùng chia sẻ image mới với người khác để họ có thể tạo container từ nó.
Bước 8 – Đẩy Docker Images lên Docker Repository
Bước tiếp theo sau khi tạo image mới từ một image hiện có là chia sẻ nó với một vài người bạn, với cả thế giới trên Docker Hub hoặc các Docker registry khác mà bạn có quyền truy cập. Để đẩy một image lên Docker Hub hoặc bất kỳ Docker registry nào khác, bạn phải có tài khoản tại đó.
Để đẩy image của bạn, trước tiên đăng nhập vào Docker Hub:
docker login -u docker-registry-username
Bạn sẽ được yêu cầu xác thực bằng mật khẩu Docker Hub của mình. Nếu nhập đúng mật khẩu, quá trình xác thực sẽ thành công.
Lưu ý: Nếu tên người dùng Docker registry của bạn khác với tên người dùng cục bộ mà bạn đã dùng để tạo image, bạn sẽ phải gán nhãn (tag) image của mình với tên người dùng registry. Ví dụ, trong bước trước, bạn sẽ gõ:
docker tag sammy/ubuntu-nodejs docker-registry-username/ubuntu-nodejs
Sau đó, bạn có thể đẩy image của mình lên bằng lệnh:
docker push docker-registry-username/docker-image-name
Để đẩy image ubuntu-nodejs
lên repository của sammy, lệnh sẽ là:
docker push sammy/ubuntu-nodejs
Quá trình này có thể mất một chút thời gian khi image được tải lên, và khi hoàn tất, kết quả sẽ hiển thị như sau:
Output The push refers to a repository [docker.io/sammy/ubuntu-nodejs] e3fbbfb44187: Pushed 5f70bf18a086: Pushed a3b5c80a4eba: Pushed 7f18b442972b: Pushed 3ce512daaf78: Pushed 7aae4540b42d: Pushed ...
Sau khi đẩy image lên registry, image đó sẽ được liệt kê trên dashboard của tài khoản bạn, như hình minh họa bên dưới.
Nếu quá trình đẩy (push) bị lỗi với thông báo như sau, có khả năng bạn chưa đăng nhập:
Output The push refers to a repository [docker.io/sammy/ubuntu-nodejs] e3fbbfb44187: Preparing 5f70bf18a086: Preparing a3b5c80a4eba: Preparing 7f18b442972b: Preparing 3ce512daaf78: Preparing 7aae4540b42d: Waiting unauthorized: authentication required
Hãy đăng nhập lại bằng lệnh docker login
và thử đẩy lại. Sau đó, xác nhận rằng image đã xuất hiện trên trang repository Docker Hub của bạn.
Bạn bây giờ có thể dùng lệnh docker pull sammy/ubuntu-nodejs
để tải image về một máy mới và dùng nó để chạy container mới.