2. Docker Image và Docker Container
Ở bài học trước, bạn đã biết được:
- Docker là một nền tảng, giúp bạn đóng gói ứng dụng cùng với thư viện và môi trường cần thiết thành một Docker Image, gửi Docker Image này tới máy tính khác và chạy Docker Image này để tạo thành Docker Container
- Bạn cũng đã cài đặt được phần mềm Docker Desktop. Phần mềm này chứa Docker Engine, là công cụ để tạo ra Docker Image, chạy Docker Image để tạo thành Docker Container
Trong bài học này, chúng ta sẽ tìm hiểu về cách tạo Docker Image, chạy Docker Image để tạo thành Docker Container và các chủ đề liên quan.
2.1 Docker Image
Docker Image là gì?
Docker Image có thể được hiểu là một bản thiết kế (blueprint) hoặc một khuôn mẫu đóng băng của một môi trường máy tính. Nó là một tập tin, chứa tất cả những thứ cần thiết để một ứng dụng có thể chạy được, bao gồm: mã nguồn, thư viện, các công cụ hệ thống và các thiết lập cấu hình.
Đặc điểm của Docker Image
- Tính bất biến (Read-only): Khi một Docker Image đã được tạo ra (build), bạn không thể thay đổi nội dung bên trong nó. Nếu muốn thay đổi, bạn phải tạo một Docker Image mới
- Cấu trúc lớp (Layered): Docker Image được xây dựng từ nhiều lớp xếp chồng lên nhau. Mỗi dòng lệnh trong tập tin cấu hình sẽ tạo ra một lớp mới
- Nhẹ và nhanh: Vì các lớp có thể được tái sử dụng giữa các Docker Image khác nhau, nên việc lưu trữ và truyền tải Docker Image trở nên rất hiệu quả
Để dễ hiểu, bạn hãy hình dung khi làm bánh, Docker Image chính là Công thức làm bánh: Nó là tờ giấy ghi rõ bạn cần bao nhiêu bột, bao nhiêu trứng, nướng ở nhiệt độ nào. Bản thân tờ giấy này không ăn được, nó chỉ là "hướng dẫn" và "nguyên liệu chuẩn bị sẵn".
Ví dụ 1: Giả sử bạn có một ứng dụng web viết bằng Python. Docker Image của ứng dụng này sẽ đóng gói:
- Hệ điều hành rút gọn (ví dụ: Ubuntu hoặc Alpine Linux)
- Phiên bản Python cụ thể (ví dụ: Python 3.9)
- Các thư viện cần thiết (như Flask hoặc Django)
- Mã nguồn ứng dụng do bạn viết
Ví dụ 2: Giả sử bạn có một ứng dụng web viết bằng Express. Docker Image của ứng dụng này sẽ đóng gói:
- Hệ điều hành rút gọn
- Môi trường thực thi Node
- Các thư viện cần thiết (dependencies)
- Mã nguồn ứng dụng
- Cấu hình và chỉ thị thực thi
2.2 Docker Container
Docker Container là gì?
Nếu Docker Image là "bản thiết kế" hay “khuôn mẫu đóng băng của một môi trường máy tính”, thì Docker Container chính là thực thể sống đang hoạt động được tạo ra từ bản thiết kế đó hay là một môi trường máy tính đã được rã băng (đang chạy).
Khi bạn "chạy" một Docker Image, Docker Engine sẽ giải nén các lớp của Docker Image và tạo ra một môi trường biệt lập để ứng dụng vận hành.
Trong làm bánh, nếu coi Docker Image là công thức làm bánh, thì Docker Container chính là chiếc bánh thật (được bạn tạo ra từ công thức). Bạn có thể dùng 1 công thức (Docker Image) để làm ra 10 chiếc bánh (Docker Container) giống hệt nhau.
Đặc điểm của Docker Container
- Tính tạm thời: Khác với Docker Image là bất biến, Docker Container có thể được tạo ra, khởi động, dừng lại hoặc xóa đi bất cứ lúc nào mà không ảnh hưởng đến Docker Image gốc
- Tính biệt lập (Isolated): Mỗi Docker Container chạy trong một không gian riêng. Một lỗi xảy ra trong Docker Container này thường không làm ảnh hưởng đến các Docker Container khác hay hệ điều hành chính của bạn
- Khả năng ghi: Khi một Docker Container khởi động, Docker thêm một “lớp đệm mỏng” có thể ghi lên trên các lớp Read-only của Docker Image. Mọi thay đổi bạn thực hiện khi ứng dụng đang chạy (như tạo tập tin mới) sẽ được lưu ở lớp này
2.3 Quy trình Build - Ship - Run
Khi làm việc với Docker, bạn sẽ thường xuyên thực hiện 3 bước sau:
(Để tiện trình bày, từ đây sẽ gọi tắt Docker Image là Image, Docker Container là Container.)
Các bước gồm:
Build (Xây dựng) > Ship (Chuyển giao) > Run (Khởi chạy)
- Bước 1: Build (tạo Image)
Đây là giai đoạn bạn đóng gói ứng dụng tại máy tính cá nhân (máy phát triển)
- Bước 2: Ship (Chuyển giao Image sang máy tính khác)
Sau khi có Image, bạn cần đưa nó tới máy tính của đồng nghiệp hoặc máy chủ (Server).
- Bước 3: Run (Chạy Image để tạo Container)
Đây là giai đoạn cuối, mở và chạy ứng dụng trên máy của đồng nghiệp hoặc trên server.
Xem hình minh họa:
2.4 Thực hành quy trình Build-Ship-Run
2.4.1 Tạo Image
Bạn thực hiện đóng gói ứng dụng tại máy tính cá nhân (máy phát triển), để tạo Image. Công việc gồm: viết một tập tin Dockerfile (bản hướng dẫn). Khi chạy lệnh docker build, Docker Engine sẽ đọc bản hướng dẫn này để gom: hệ điều hành, thư viện và mã nguồn lại thành một tập tin duy nhất gọi là Image.
Chúng ta cùng thực hành đóng gói một ứng dụng web gồm các thành phần sau:
- Một thư mục dự án
- Trong thư mục dự án có một tập tin mã nguồn HTML, trang index.html, nội dung trang web hiển thị lời chào “Chào bác Tèo”
- Ứng dụng web chạy trên web server Nginx
Các bước thực hiện:
Bước 1. Chuẩn bị các thành phần
- Tạo thư mục dự án teo-docker-project
- Trong thư mục dự án, tạo tập tin index.html với nội dung: <h1>Chào bác Tèo</h1>
Bước 2. Viết tập tin Dockerfile
Một cách dễ hiểu, nếu Container là một cái bánh, thì Dockerfile là tờ giấy viết công thức làm bánh.
Trong Docker, Dockerfile là một tập tin văn bản (text), không có phần mở rộng (đuôi), chứa một tập hợp các câu lệnh (instructions) nối tiếp nhau. Docker sẽ đọc tập này, thực thi các lệnh, để đóng gói thành một Docker Image.
- Trong thư mục teo-docker-project, tạo tập tin Dockerfile (lưu ý: không có đuôi)
- Nhập nội dung sau cho tập tin Dockerfile
[Dockerfile]
# 1. Chọn hệ điều hành rút gọn có sẵn máy chủ web (Nginx)
FROM nginx:alpine
# 2. Chép mã nguồn (tập tin index.html) từ máy tính (máy của lập trình viên) vào đúng vị trí trong Image
COPY index.html /usr/share/nginx/html/index.html
Bước 3. Thực hiện lệnh “build” để tạo Image
Bây giờ, chúng ta sẽ ra lệnh cho Docker Engine đọc và thực thi từng lệnh trong Dockerfile để "gom" mọi thứ lại.
- Mở PowerShell/Command Prompt của hệ điều hành Windows
- Di chuyển vào thư mục dự án của bạn bằng lệnh cd:
cd đường/dẫn/đến/thư-mục/my-docker-project
- Chạy lệnh đóng gói:
docker build -t hello-docker-image:v1 .
Trong đó,
- docker build: lệnh của docker để tạo Image từ Dockerfile
- tham số -t (viết tắt của tag), được sử dụng để gán nhãn cho Image là hello-docker-image
- v1: là phiên bản của Image (v là viết tắt của version)
- . : dấu chấm ở cuối, đại diện cho thư mục hiện hành. Nó báo cho Docker rằng: "Hãy tìm Dockerfile và các tập tin liên quan ngay tại đây".
Bước 4: Kiểm tra thành quả trên Docker Desktop
Sau khi chạy lệnh docker build xong, và không có lỗi, Docker Engine sẽ tạo ra một Image, tên là hello-docker-image. Để kiểm tra:
- Mở ứng dụng Docker Desktop
- Nhấp vào mục Images ở cột bên trái
- Bạn sẽ thấy một bản ghi mới, tên là hello-docker-image với dung lượng rất nhỏ (khoảng vài chục MB)
Giải thích quá trình thực thi lệnh build:
Khi bạn chạy lệnh build, Docker đã thực hiện đúng như nội dung đã viết trong Dockerfile:
- Tải về hệ điều hành alpine có cài sẵn web server nginx
- Lấy tập tin index.html từ máy tính của bạn, đặt vào trong web server
- Tạo ra một tập tin duy nhất, tên là hello-docker-image: đây là một tập tin tĩnh, không thay đổi, chứa tất cả những gì cần thiết (hệ điều hành, web server và một trang index.html) để chạy trang web của bạn ở bất cứ đâu.
2.4.2 Chuyển giao Image sang máy tính khác (Ship)
Khi bạn đã tạo được Image và muốn chuyển nó tới máy tính khác (máy của đồng nghiệp hoặc máy server), có 2 cách làm:
- Gửi Image như một tập tin thông thường
- Dùng Docker Registry
Gửi Image như một tập tin thông thường:
Cách này phù hợp khi bạn muốn chép Image qua đĩa USB, hoặc gửi qua mạng nội bộ mà không muốn tải lên mạng, hoặc bạn không muốn sử dụng hệ thống Docker Registry.
Chúng ta sẽ xuất Image thành một tập tin:
- Sử dụng lệnh docker save
docker save -o hello-image.tar hello-docker-image:v1
Trong đó:
- docker save: lệnh của docker để xuất Image thành tập tin
- Tham số -o: viết tắt của output (xuất)
- hello-image.tar: tên của tập tin kết quả, nén theo kiểu tar
- hello-docker-image:v1: tên của Image sẽ được xuất thành tập tin
Nếu chạy lệnh docker save thành công, bạn sẽ thấy xuất hiện tập tin hello-image.tar tại thư mục teo-docker-project.
Bạn có thể chép tập tin hello-image.tar sang máy tính khác bằng đĩa USB, mạng nội bộ, Google Drive, Zalo,...v.v.
Nạp Image vào Docker tại máy nhận
Tại máy nhận, bạn mở chương trình cửa sổ dòng lệnh (CMD, chạy lệnh docker load:
docker load i hello-image.tar
Trong đó:
- docker load: lệnh của docker để nạp Image đang ở dạng tập tin nén
- i là viết tắt của input (nhập)
- hello-image.tar: tên của tập tin nén đang chứa Image
docker load -i hello-image.tar
Sau khi chạy thành công, bạn sẽ thấy Image xuất hiện trong cửa sổ của Docker Engine, giống như bạn vừa build nó
(Nếu bạn thực hành trên một máy tính, thì bạn phải xóa Image có tên là hello-docker-image trong Docker Engine, sau đó thực hiện docker load để thấy Image mới)
Dùng Docker Registry:
Đây là cách chuyên nghiệp, được sử dụng nhiều. Cách này giống như khi bạn đẩy mã nguồn lên Github.
Bạn sẽ đẩy Image lên một “kho” chung trên mạng, rồi các máy tính khác sẽ tải về.
Gắn thẻ (tag) cho Image:
Bạn nên hiểu là Image là một thùng hàng, trên thùng hàng này, bạn sẽ dán thêm các thẻ tùy ý, để dùng trong việc vận chuyển, lưu kho, …v.v.
Bạn sẽ gắn thêm thẻ mới cho Image, thẻ này chứa tên tài khoản và tên của Image, để khi đẩy lên mạng, hệ thống sẽ biết được đẩy Image này vào tài khoản của bạn. Cấu trúc của thẻ mới là: <tên_tài_khoản>/<tên_image>:<tag>
Ví dụ, sử dụng lệnh docker tag để gắn thêm thẻ:
docker tag hello-docker-image:v1 username/hello-docker-image:v1
Trong đó:
- docker tag: là tên lệnh
- hello-docker-image:v1: tên của Image sẽ được gắn thẻ
- username/hello-docker-image:v1: tên của thẻ gắn thêm, username là tên tài khoản trên Docker Hub
Đăng nhập vào Docker Hub:
(Bạn phải có tài khoản trên Docker Hub, nếu chưa có bạn phải tạo tài khoản để thực hành tiếp. Vào trang https://hub.docker.com/ để tạo tài khoản)
Tại cửa sổ dòng lệnh, nhập lệnh:
docker login
Nhập username và mật khẩu
Đẩy Image lên (Push):
docker push username/hello-docker-image:v1
Ví dụ:
D:\Demos\teo-docker-project>docker push conglg/hello-docker-image:v1
The push refers to repository [docker.io/conglg/hello-docker-image]
6b7b6c7061b7: Pushed
5e7756927bef: Pushed
399d0898a94e: Pushed
589002ba0eae: Pushed
5507cfe23e78: Pushed
1b2e1c54005d: Pushed
955a8478f9ac: Pushed
6d397a54a185: Pushed
bca5d04786e1: Pushed
3e2c181db1b0: Pushed
v1: digest: sha256:aea402027e6a468f3f623b497b83c714d64cbd07c22ec33939bbb6c431ff8e43 size
Tại máy tính khác:
Bạn chỉ cần chạy lệnh sau để lấy Image về máy:docker pull username/hello-docker-image:v1
