Tìm hiểu về Container - Docker và Podman
Container là một công nghệ mà cho phép chúng ta chạy một chương trình trong một môi trường độc lập hoàn toàn với các chương trình còn lại trên cùng một máy tính. Vậy container làm được việc đó bằng cách nào?
Và thật ra để làm được việc đó thì container nó được xây dựng từ một vài tính năng mới của Linux kernel, trong đó hai tính năng chính là “namespaces” and “cgroups”. Đây là hai tính năng của Linux giúp ta tách biệt một process hoàn toàn độc lập với các process còn lại. Tham khảo
Docker là một công cụ giúp cho việc tạo ra và triển khai các Container để phát triển, chạy ứng dụng được dễ dàng. Các container là môi trường, mà ở đó lập trình viên đưa vào các thành phần cần thiết để ứng dụng của họ chạy được, bằng cách đóng gói ứng dụng cùng với container như vậy, nó đảm bảo ứng dụng chạy được và giống nhau ở các máy khác nhau (Linux, Windows, Desktop, Server ...)
Docker có vẻ rất giống máy ảo (nhiều người từng tạo máy ảo với công cụ ảo hóa như Virtual Box, VMWare), nhưng có điểm khác với VM: thay vì tạo ra toàn bộ hệ thống (dù ảo hóa), Docker lại cho phép ứng dụng sử dụng nhân của hệ điều hành đang chạy Docker để chạy ứng dụng bằng cách bổ sung thêm các thành phần còn thiếu cung cấp bởi container. Cách này làm tăng hiệu xuất và giảm kích thước ứng dụng.
Giới thiệu về Docker làm quen với Docker tạo container
Tuy nhiên, ở trong mảng quản lý containers này cũng còn rất nhiều công cụ khác có thể thay thế Docker được, Podman là một trong những công cụ đó.
Podman là một mã nguồn mở được phát triển bởi Redhat, là một công cụ dùng để quản lý, xây dựng và chạy containers.
Nếu bạn biết Kubernetes thì Redhat đã thiết kế Podman để làm việc với K8S, nên nếu ta xài K8S thì Podman là lựa chọn tốt hơn so với Docker.
Nếu bạn đã xài Docker thì thao tác với Podman sẽ rất đơn giản, vì Podman có toàn bộ câu lệnh của Docker. Nếu bạn đang xài Docker trên Linux và muốn chuyển sang Podman thì chỉ đơn giản thêm đoạn alias docker=podman vào file ~/.bashrc.
Cài đặt Docker
# -- For Ubuntu
sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
sudo apt update
apt-cache policy docker-ce
# -- Cài đặt
sudo apt install docker-ce
# -- Kiểm tra trạng thái
sudo systemctl status docker
# -- Kiểm tra version
docker --version
# -- Có thể cho user hiện tại thuộc group docker, để khi gõ lệnh không cần xin quyền sudo
sudo usermod -aG docker $USER
# -- Khi sử dụng đến thành phần docker-compose thì bạn cài thêm
sudo apt install docker-compose
# -- Logout sau đó login lại để có hiệu lực.
# -- For Centos 7
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce
# -- cho user hiện tại thuộc group docker, để khi gõ lệnh không cần xin quyền sudo
sudo usermod -aG docker $(whoami)
# -- Start
sudo systemctl enable docker.service
sudo systemctl start docker.service
# -- Kiểm tra version
docker --version
# -- Cài thêm Docker Compose
sudo yum install epel-release
sudo yum install -y python-pip
sudo pip install docker-compose
sudo yum upgrade python*
# -- Kiểm tra version
docker-compose version
# -- Kiểm tra thông tin Docker
docker --version
# -- Chi tiết hơn, kiểm tra số lượng images, container đang chạy và trạng thái của nó
docker info
Image và Container trong Docker
Image là một gói phần mềm trong đó chứa những thứ cần như thư viện, các file cấu hình, biến môi trường để chạy mội ứng dụng nào đó. Nó giống như cái USB chứa bộ cài đặt hệ điều hành Windows!
Khi một phiên bản của Image chạy, phiên bản chạy đó gọi là Container - (vậy muốn có container phải có image). Bất cứ lúc nào bạn cũng có thể kiểm tra xem có bao nhiêu container đang chạy và nó sinh ra từ image nào.
Image có thể được tải về từ https://hub.docker.com.
Tải về 1 Image
# -- Kiểm tra các image hiện có
docker images -a
Repository tên image trên kho chứa, ví dụ hệ điều hành CentOS có tên trên hub.docker.com là centos (xem centos) TAG là phiên bản image, với giá trị latest có nghĩa là bản cuối. Muốn tải về bản khác latest vào mục TAGS trên hub.docker.com tìm bản phù hợp. IMAGE ID một chuỗi định danh duy nhất (tên) của image trên hệ thống của bạn.
# -- Tải về 1 image nào đó dùng lệnh
docker pull nameimage:tag
# -- Hoặc tải về bản cuối
docker pull nameimage
# -- Ex :
docker pull ubuntu
# -- dùng lệnh để kiểm tra
docker images -a
Tạo và chạy Container
# -- Kiểm tra các container đang chạy
docker ps
# -- hay
docker container ls --all
CONTAINER ID một con số (mã hash) gán cho container, bạn dùng mã này để quản lý container này, như xóa bỏ, khởi động, dừng lại ... IMAGE cho biết container sinh ra từ image nào. COMMAND cho biết lệnh, ứng dụng chạy khi container chạy (/bin/bash là terminate) STATUS cho biết trạng thái, (exit - đang dừng)
Để tạo và chạy container theo cú pháp
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
[OPTIONS] các thiết lập khi tạo container, có rất nhiều thiết lập tùy mục đích tạo container, sẽ tìm hiểu các thiết lập qua từng trường hợp cụ thể. IMAGE tên image hoặc ID của image từ nó sinh ra container. [COMMAND] [ARG...] lệnh và tham số khi container chạy.
docker run -it ubuntu
# -- Run docker với name, dùng name thay cho containerid
docker run -it --name myubuntu ubuntu
Bạn chú ý có tham số -it để khi container chạy, bạn có terminate làm việc ngay với Ubuntu. Tham số này có nghĩa là
-t nó có nghĩa là console, cho phép kết nối với terminal để tương tác.
-i có nghĩa duy trì mở stdin để nhập lệnh.
Khi đang trong container, có thể dùng lệnh exit để thoát, nhưng container vẫn chạy bình thường.
# -- Tạo và chạy container, container tự xóa khi kết thúc thì thêm vào tham số --rm
docker run -it --rm ubuntu
# -- Tạo và chạy container - khi container chạy thi hành ngay một lệnh nào đó, ví dụ ls -la
docker run -it --rm debian ls -la
# -- Tạo và chạy container - ánh xạ một thự mục máy host vào một thư mục container, chia sẻ dữ liệu
docker run -it --rm -v [path-in-host]:[path-in-container] debian
Để vào container đang chạy. Kiểm tra bằng lệnh docker ps, xem container với ID là containerid đang chạy
docker container attach [containerid]
# -- Chạy một container đang dừng
docker container start -i containerid
# -- Nếu cần xóa bỏ hẳn một container thì dùng lệnh
docker container rm containerid
Tóm tắt các lệnh làm quen
# -- kiểm tra phiên bản
docker --version
# -- liệt kê các image
docker images -a
# -- xóa một image (phải không có container nào đang dùng)
docker images rm [imageid]
# -- tải về một image (imagename) từ hub.docker.com
docker pull [imagename]
# -- liệt kê các container
docker container ls -a
# -- xóa container
docker container rm [containerid]
# -- tạo mới một container
docker run -it [imageid]
# -- Vào termial container đang chạy
docker container attach [containerid]
# -- Chạy container đang dừng
docker container start|stop -i [container_name](or [containerid])
# -- Chạy một lệnh trên container đang chạy
docker exec -it [containerid] [command]
Lưu Container thành Image và nạp Image đã lưu thành Container mới
Như đã nói, một Image bạn có thể sinh ra các Container, mỗi Container là bản thực thi của Image, khi sử dụng Container bạn có thể cấu hình, cài đặt thêm vào nó các package, đưa thêm dữ liệu ...
Đến một lúc, bạn muốn lưu những thay đổi này và ghi lại thành một Image để sau này bạn sinh ra các Container khác bản thân nó đã chữa những thay đổi bạn đã lưu.
Lưu Container thành Image
Giả sử bạn có một container có tên (hoặc id) là mycontainer nếu muốn lưu thành image thực hiện lệnh. Trong đó myimage và version là tên và phiên bản do bạn đặt. Nếu lưu cùng tên với image tạo ra container này, coi như image cũ được cập nhật mới.
docker commit mycontainer myimage:version
Ví dụ: ta sẽ tạo một phiên bản Centos mới có cài thêm gói SSH Client, lưu container này lại thành image và tạo một container mới từ từ image đã lưu này.
# -- 1.Tải hệ điều hành centos về nếu chưa có
docker pull centos
# -- 2.Tạo/chạy một container đặt tên là mycentos của centos
docker run -it --name mycentos centos
# -- 3.Cài SSH Client vào container mycentos
yum install openssh-clients
# -- 4.Lưu container lại thành image: trước tiên nếu container đang chạy thì cho dừng lại
docker stop mycontainer
# -- Gõ lệnh lưu container mycontainer thành image đặt tên là centos-ssh:v1
docker commit mycentos centos-ssh:v1
# -- Xóa container cũ
docker container rm mycentos
# -- Tạo mới từ image centos-ssh:v1
docker run --name newcontainer -it centos-ssh:v1
Lưu Image ra file, nạp Image từ file đã lưu
Nếu muốn chia copy image ra máy khác ngoài cách đưa lên repository có thể lưu ra file, lệnh sau lưu image có tên myimage ra file
# -- Lưu ra file, có thể chỉ ra đường dẫn đầy đủ nơi lưu file
docker save --output myimage.tar myimage
File này có thể lưu trữ, copy đến máy khác và nạp vào docker, để nạp vào docker.
# -- Load file thành Docker Image
docker load -i myimage.tar
# -- Đổi tên một Image đang có
docker tag image_id imagename:version
Chia sẻ dữ liệu giữa Docker Host và Container
Container ánh xạ thư mục với máy Host
Máy Host là hệ thống bạn đang chạy Docker Engine. Chúng ta sẽ tìm hiểu cách chia sẻ dữ liệu giữa máy Host và Container, giữa các Container với nhau bằng cách sử dụng một thư mục trên máy Host làm nơi lưu trữ tập trung.
Thư mục cần chia sẻ dữ liệu trên máy host là: path_in_host
Khi chạy container thư mục đó được mount - ánh xạ tới path_in_container của container
Để có kết quả đó, tạo - chạy container với tham số thêm vào -v path_to_data:path_in_container. Nếu có nhiều thư mục cần share thì thêm các khối -v path_to_data:path_in_container
docker run -it -v /home/sitesdata:/home/data ubuntu
Lúc này, dữ liệu trên thư mục /home/sitesdata/ của máy Host thì trong Container có thể truy cập, cập nhật sửa đổi ... thông qua đường dẫn /home/data. Thư mục /home/data này không cần tạo trước trong Container
Chia sẻ dữ liệu giữa các Container
Có container với id hoặc name là container_first, trong đó nó có mount thư mục Host vào (hoặc đã được chia sẻ tử Container khác). Giờ chạy, tạo container khác cũng nhận thư mục chia sẻ dữ liệu như container_first. Để làm điều đó thêm vào tham số --volumes-from container_first
docker run -it --volumes-from container_first ubuntu
# -- OR
docker run -it --name container_second --volumes-from container_first ubuntu
# -- Tạo container_second nhận thư mục chia sẻ như container_first
Bạn đã tạo ra một Container nhận thư mục chia sẻ như container có ID hoặc tên là container_first tạo trước đó.
Quản lý các ổ dĩa với Docker Volume
# -- Liệt kê danh sách các ổ đĩa
docker volume ls
# -- Tạo một ổ đĩa
docker volume create [name_volume]
# -- Xem thông tin chi tiết về đĩa
docker volume inspect [name_volume]
# -- Xóa một ổ đĩa
docker volume rm [name_volume]
# -- Xóa tất cả các ổ đĩa không được sử dụng bởi container nào
docker volume prune
Mount một ổ dĩa vào Container (--mount)
# -- Tạo ổ đĩa có tên firstdisk
docker volume create firstdisk
# -- Mount ổ đĩa vào container
docker run -it --mount source=firstdisk,target=/home/firstdisk ubuntu
# -- container truy cập tại /home/firstdisk
Gán ổ dĩa vào Container khi tạo Container (-v)
# -- Nếu muốn ổ đĩa bind dữ liệu đến một thư mục cụ thể của máy HOST thì tạo ổ đĩa với tham số như sau:
docker volume create --opt device=[path_in_host] --opt type=none --opt o=bind [volumename]
# -- Sau đó ổ đĩa này gán vào container với tham số -v (không dùng --mount)
# Tạo ổ đĩa có tên mydisk (dữ liệu lưu tại /home/mydata)
docker volume create --opt device=/home/mydata --opt type=none --opt o=bind mydisk
# Gán ổ đĩa vào container tại (/home/sites)
docker run -it -v mydisk:/home/sites ubuntu
Network bridge trong Docker, kết nối các Container với nhau
Network trong Docker, liên kết mạng các Container với nhau
# -- Liệt kê các network đang có
docker network ls
Các network được tạo ra theo một driver nào đó như bridge, none, overlay, macvlan. Trong phần này sẽ sử dụng đến bridge network. Nó cho phép các container cùng network này liên lạc với nhau, cho phép gửi gói tin ra ngoài. Tạo một bridge network với tên network là name-network.
docker network create --driver bridge name-network
Khi tạo một container, ấn định nó nối vào network có tên là name-network thì thêm vào tham số --network name-network trong lệnh docker run. Khi một container có tên name-container đã được tạo, để thiết lập nó nối vào network có tên name-network.
# -- Ấn định network khi chạy
docker run -it --network name-network ubuntu
# -- Thiết lập kết nối với name-container
docker network connect name-network name-container
Các kết nối mạng thông qua các cổng/port, để thiết lập cấu hình các cổng của container. Chú ý: có cổng bên trong container, có cổng mở ra bên ngoài (public), có giao thức của cổng (tpc, udp). Khi chạy container (tạo) cần thiết lập cổng thì đưa vào lệnh docker run tham số dạng sau:
docker run -p public-port:target-port/protocol ...
public-port : cổng public ra ngoài (ví dụ 80, 8080 ...), các kết nối không cùng network đến container phải thông qua cổng này. target-port : cổng bên trong container, cổng public-port sẽ ánh xạ vào cổng này. Nếu các container cùng network có thể kết nối với nhau thông qua cổng target-port này.
Thực hành ví dụ tạo 3 container chạy 3 dịch vụ. Dùng mạng bridge để liên kết các Container này.
Thực hành tạo ra 3 container, chạy 3 dịch vụ khác nhau là httpd, php-fpm, mysql. Tạo một mạng bridge để liên kết những container này với nhau (giao tiếp với nhau qua cổng nội bộ httpd:80, php-fpm:9000, mysql:443). Trong đó thiết lập thêm httpd mở cổng public 8080 trên máy host để ánh xạ vào 80 của nó.
Tạo container PHP trên Docker
Chọn cài đặt php:7.3-fpm (các phiên bản khác tương tự) đây là PHP 7.3 cài đặt sẵn PHP-FPM, mặc định cho phép apache gọi đến PHP thông qua proxy với cổng 9000, xem thêm Apache Handler PHP Handler, phù hợp để tạo một container riêng chuyên chạy PHP.
# -- Tạo một container chạy PHP từ image php:7.3-fpm, đặt tên container này là c-php
docker run -d --name c-php -h php -v /mycode/php:/home/phpcode php:7.3-fpm
-d : container sau khi tạo chạy luôn ở chế độ nền. --name c-php : container tạo ra và đặt luôn cho nó tên là c-php (Tương tác với container dễ đọc hơn khi sử dụng tên thay vì phải sử dụng mã hash id, nếu không đặt tên thì docker sinh ra tên ngẫu nhiên). -h php : đặt tên HOSTNAME của container là php -v "/mycode/php":/home/phpcode thư mục trên máy host /mycode/php (với Windows đường dẫn theo OS này như "c:\path\mycode\php") được gắn vào container ở đường dẫn /home/phpcode. php:7.3-fpm là image khởi tạo ra container, nếu image này chưa có nó tự động tải về.
# -- Một container đã tạo container có tên đặt là c-php từ image php:7.3-fpm. Hãy kiểm tra:
docker ps -a
Giờ nếu muốn nhảy vào tương tác với container này (container phải đang chạy), thì gọi lệnh bash của nó bằng cách:
docker exec -it c-php bash
# -- Đang trong PHP shell, ta có thể thực hiện các lệnh
# -- Kiểm tra phiên bản PHP
php -v
# -- Chạy test chức năng PHP. /home/phpcode/ là thư mục chia sẻ với máy host
cd /home/phpcode/
echo "<?php echo 'Hello World';" > test.php
# -- Chạy test.php
php test.php
#Kết quả: Hello World!
Cài đặt thêm các modules cho PHP
# -- Có sẵn một script có tên là docker-php-ext-configure và docker-php-ext-install để bạn cấu hình, cài các # Extension cho PHP, ví dụ nếu muốn có thêm OpCache thì gõ:
docker-php-ext-configure opcache --enable-opcache \
&& docker-php-ext-install opcache
# -- Cài thêm mysqli - extension để kết nối PHP đến MySQL
docker-php-ext-configure opcache --enable-mysqli \
&& docker-php-ext-install mysqli
# -- Cài thêm pdo_mysql - extension để kết nối PHP đến MySQL với thư viện PDO
docker-php-ext-configure opcache --enable-pdo_mysql \
&& docker-php-ext-install pdo_mysql
# -- Để có trình soạn thảo text nano gõ lệnh
apt-get update && apt-get install nano
# -- Chỉnh sửa thiết lập nào đó
nano /usr/local/etc/php/php.ini
# -- Kiểm tra các phần mở rộng đã có trong PHP bằng lệnh, cần module nào thì cài thêm vào
php -m
# -- Khi cài đặt extension, thay đổi thiết lập để hiệu lực hãy khởi động lại container này bằng lệnh:
docker restart c-php
Tạo container APACHE HTTPD trên Docker
# -- Apache là máy chủ HTTPD rất phổ biến, nhất là các server Linux. Tải về httpd bản mới nhất:
docker pull httpd
# -- Tạo một container httpd đặt tên là c-httpd
docker run -di -p 8080:80 -p 443:443 --name c-httpd -h httpd -v /mycode/php:/home/phpcode httpd
# -- Kiểm tra
docker ps -a
Trong lệnh trên, có tham số -p 8080:80 để thiết lập cổng cho container, nếu không thiết lập thì mặc định một container không mở cổng nào cả, với thiết lập trên - khi truy cập cổng 8080 trên HOST, sẽ ánh xạ vào cổng 80 của container, cổng mà máy chủ httpd đang lắng nghe.
Giờ từ trình duyệt, vào địa chỉ httpd://localhost:8080 thấy có kết quả.
Chỉnh sửa file config httpd.conf
Thì ta nhảy vào bash shell của container. File config tại: /usr/local/apache2/conf/httpd.conf. Nếu muốn cài trình soạn thảo nano gõ lệnh apt-get update & apt-get install nano. Restart container sau khi chỉnh sửa docker restart c-httpd
Thiết lập PHP Handle
Ứng dụng PHP nằm ở container c-php, tên này nếu cũng dùng để container khác cùng mạng liên lạc đến mà không cần dùng IP cụ thể, (Ở phần sau sẽ thiết lập 2 container này cùng nối vào một network). Vì vậy, thêm vào httpd.conf dòng cấu hình sau để khi truy vấn đến file .php thì nó sẽ chạy PHP từ Proxy:
AddHandler "proxy:fcgi://c-php:9000" .php
Do Handler này gọi PHP thông qua proxy, nên Apache phải kích hoạt module liên quan đến proxy, mở file httpd.conf và bỏ commnet trên các dòng:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
# -- Sửa xong khởi động lại apache:
apachectl -k restart
Liên kết APACHE và PHP-FPM
Để hai container c-php và c-httpd liên lạc được với nhau (ví dụ từ httpd với proxy:fcgi://c-php:9000), thì ta thiết lập chúng cùng một mạng.
# -- Tạo ra một mạng với Driver là bridge đặt tên là www-net
docker network create --driver bridge www-net
# -- Xem lại
docker network ls
# -- Thiết lập container c-php và c-httpd nối vào mạng này.
docker network connect www-net c-php
docker network connect www-net c-httpd
# -- Kiểm tra thông tin mạng www-net
docker network inspect www-net
"Containers": {
"a0112f016627ee477376bdbd93fdf2948d55b54d2326fb488865592a99f3be1c": {
"Name": "c-httpd",
"EndpointID": "bd2e5af336ddb27891bb130c53c6707f4090a0ffcf67068d0f4762cd45eeafdb",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"c4dd6ecd43b48d47653fed19bc7fea483c378f807bf08b6fda42ac7b7d35fcff": {
"Name": "c-php",
"EndpointID": "2464bdc048650e87484c89a73f04f7b582a6ad2840f7d7095ffe5360a0e572ff",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
Như vậy 2 container trên đã cùng một network với địa chỉ IP cho từng container. Hai container này đã có thể liên lạc với nhau qua giao tiếp mạng, bạn có thể kiểm tra bằng cách vào container này và dùng lệnh ping đến IP của container kia.
# -- Cài đặt lệnh ping nếu cần
apt-get update && apt-get install iputils-ping -y
# -- ping IP/hostname đã đặt (-h option trong lệnh run)
ping 172.18.0.3 / ping http
Đến đây thì đã Apache đã gọi được PHP, ta sẽ thử cấu hình và chạy một file php. Trước tiên, mở httpd.conf và chỉnh sửa thư mục gốc mặc định nằm ở /home/phpcode. Tìm đến:
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
# -- Thay bằng
DocumentRoot "/home/phpcode"
<Directory "/home/phpcode">
# -- Hãy tạo file /home/phpcode/test.php
nano /home/phpcode/test.php
# -- nội dung
<?php phpinfo();
Từ máy Host vào trình duyệt với địa chỉ, http://localhost:8080/index.php kiểm tra nội dung.
Tạo container MYSQL trên Docker
# -- chạy container từ image mysql (image này nếu chưa có ở local, nó sẽ tự tải về), đặt tên là c-mysql
docker run -it --network www-net --name c-mysql -h mysql \
-v /mycode/db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=abc123 mysql
--network www-net container sẽ kết nối với mạng có tên www-net (cùng mạng với c-php, c-httpd) -e MYSQL_ROOT_PASSWORD=abc123 đặt password cho user root, quản trị mysql là abc123 -v /mycode/db:/var/lib/mysql nơi lưu trữ các database là ở thư mục /mycode/db của máy Host, làm điểu này để có không mất db khi cần xóa container, hoặc khi cần sử dụng lại các db cũ.
Sau lệnh này, bạn đang chạy MySQL cùng mạng với PHP, APACHE và cổng mở là 3306, file cấu hình ở /etc/mysql/my.cnf
Đây là mysql 8, mặc định không sử dụng plugin mysql_native_password, để các ứng dụng thông dụng kết nối dễ dàng tương thích bạn có thể chỉnh file cấu hình để sử dụng loại plugin này.
# -- Vào lại container c-mysql
docker exec -it c-mysql bash
# -- Cài đặt trình soạn thảo nano
apt-get update
apt-get install nano
# -- Mở file my.cnf
nano /etc/mysql/my.cnf
# -- Thêm nội dung
[mysqld]
default-authentication-plugin=mysql_native_password
# -- Ra khỏi container
exit
# -- Khởi động lại container c-mysql
docker restart c-mysql
Giờ thì đã có server MySQL đang chạy, các ứng dụng cùng mạng muốn sử dụng có thể kết nối đến nó qua cổng 3306. Thử thực hành vào container này và quản trị tạo một user, tạo một db
# -- nhảy vào container
docker exec -it c-mysql bash
# -- Kết nối vào MySQL Server
mysql -uroot -pabc123
# -- Từ dấu nhắc MySQL, Tạo một user tên testuser với password là testpass
CREATE USER 'testuser'@'%' IDENTIFIED BY 'testpass';
# -- Tạo db có tên db_testdb
create database db_testdb;
# -- Cấp quyền cho user testuser trên db - db_testdb
GRANT ALL PRIVILEGES ON db_testdb.* TO 'testuser'@'%';
flush privileges;
# -- Xem các database đang có, kết quả có db bạn vừa tạo
show database;
# -- Ra khỏi MySQL Server
exit;
Tạo trang web Wordpress với PHP, APCHE và MYSQL vừa tạo
Tra cứu thông tin image và giám sát các container trong Docker
Tìm hiểu cấu trúc hình thành nên container, các truy vấn và đo lường quá trình hoạt động thay đổi của container trong Docker
Các thành phần tạo nên Container
Một số khái niệm mô tả hoạt động của Docker.
Container: đó là một hộp kín để ứng dụng hoạt động. Mỗicontainerđều được tạo dựa trên mộtimage(imageđó chứa đủ cấu hình, thành phần dữ liệu). Khi bạn chạy một container xuất phát từ một image, có một lớp (layer) được phép ghi thêm vào trên đỉnh của image(vậy container = image + layer được phép ghi). Sau đó, khi bạn lưu container này thành image mới (lệnh docker commit), một lớpimagemới được thêm vào vào.Image: như là ảnh chụp lại các cấu hình của container. Mộtimageluôn ở trạng thái chỉ đọc, mọi thứ muốn thay đổi đều phải lưu ở tầng trên cùng (được phép ghi) của container, và tầng này có thể lưu lại để tạo image mới (thêm layer vào image cũ) và nó lại thành trạng thái chỉ đọc. Với quy trình như vậy, mỗi image đều phụ thuộc vào một hoặc nhiều image cha.Platform Image: là một image mà nó không có image cha. Những image loại này chứa các biến môi trường, các gói, tiện ích để ứng dụng ảo hóa chạy, nó cũng chỉ đọc.Registrylà kho chứa các image, nơi chi sẻ, tải về các image.Dockerfilemột file cấu hình với cấu trúc để sinh ra images. Sử dụng file Dockerfile là cách tự động hóa việc tạo, chạy, sử dụng các container.

Với hình ảnh trên, bạn có thể thấy hình thành cấu trúc như sau:
- Xuất phát từ một
Platform Image, chạy thành container, vậy đang hoạt động với cấu trúc gồm tầngPlatform Image+tầng được phép ghi. Lúc này thêm các thành phần vào tầng được ghi, rồi commit thành image mới. Ở image mới này, tầng được phép ghi lưu thành một tầng chỉ đọc tên image1. - Quy trình như vậy bạn có thể tạo thành nhiều tầng image khác nhau. Mỗi tầng này là chỉ đọc, chỉ có container đang chạy có tầng được phép ghi.
Truy vấn thông tin về Image và Container
Lệnh docker history
# -- Lệnh này để truy vấn thông tin lịch sử các thao tác để hình thành nên một image.
docker history [name_or_id_of_image]
# -- Ví dụ image có 91d
docker inspect 91d
IMAGE CREATED CREATED BY SIZE COMMENT
91dadee7afee 3 weeks ago /bin/sh -c #(nop) CMD ["mysqld"] 0B
3 weeks ago /bin/sh -c #(nop) EXPOSE 3306 33060 0B
3 weeks ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
3 weeks ago /bin/sh -c ln -s usr/local/bin/docker-entryp… 34B
3 weeks ago /bin/sh -c #(nop) COPY file:1667e4be6bef3129… 6.53kB
3 weeks ago /bin/sh -c #(nop) COPY dir:478f098f3681084f7… 1.22kB
3 weeks ago /bin/sh -c #(nop) VOLUME [/var/lib/mysql] 0B
Lệnh docker inspect
# -- lệnh này trả về thông tin về đối tượng cần truy vấn dưới dạng JSON. Cú pháp như sau:
docker inspect [name_or_id_of_image_container]
Ex:
docker inspect c-php
docker inspect c4dd6ecd43b4
# -- Kết quả thông tin có dạng (rất dài, đây chỉ là đoạn ngắn)
[
{
"Id": "c4dd6ecd43b48d47653fed19bc7fea483c378f807bf08b6fda42ac7b7d35fcff",
"Created": "2019-03-26T11:53:16.624300355Z",
"Path": "docker-php-entrypoint",
"Args": [
"php-fpm"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
Lệnh docker diff
# -- Lệnh docker diff để kiểm tra xem một container từ lúc nó được tạo ra đến giờ hệ thống file/thư mục thay đổi như thế nào.
docker diff [container-name-or-id]
Kết quả liệt kê ra danh sách trên từng dòng những thư mục, file có sự thay đổi. Tiền tố đầu dòng có thể là A (thêm vào add), D (bị xóa đi delete) hoặc C (được được cập nhật - change).
docker diff c-php
C /etc
A /etc/nanorc
C /etc/alternatives
A /etc/alternatives/pico
A /etc/alternatives/editor
C /home
Lệnh docker logs
# -- Để đọc thông tin log của container (mà không phải vào terminal của container)
docker logs [container-name-or-id]
docker logs c-php
# hoặc
docker logs c4dd6ecd43b4
172.18.0.3 - 26/Mar/2019:16:52:44 +0000 "GET /index.php" 200
172.18.0.3 - 26/Mar/2019:16:53:03 +0000 "GET /index.php" 200
172.18.0.3 - 26/Mar/2019:16:53:07 +0000 "GET /wp-login.php" 302
172.18.0.3 - 26/Mar/2019:16:53:07 +0000 "GET /wp-login.php" 200
172.18.0.3 - 26/Mar/2019:16:53:11 +0000 "GET /index.php" 200
172.18.0.3 - 27/Mar/2019:00:11:39 +0000 "GET /index.php" 200
172.18.0.3 - 27/Mar/2019:00:11:54 +0000 "GET /index.php" 200
[27-Mar-2019 00:58:04] NOTICE: Terminating ...
[27-Mar-2019 01:41:53] NOTICE: fpm is running, pid 1
[27-Mar-2019 01:41:53] NOTICE: ready to handle connections
Bạn có thể đưa vào một số tùy chọn sau của lệnh:
--tail n chỉ hiện thị n dòng cuối -f hoặc --follow với tham số này, nếu container đang chạy nó sẽ tự động hiện thị thêm log mới nếu container phát sinh log. Ngắt giám sát log nhấn CTRL+C
Đo lường thông tin container với docker stats
Lệnh docker stats giám sát theo thời gian thực một số lại lượng sử dụng bởi container gồm: CPU, bộ nhớ, và lưu lượng mạng, số tiến trình.
docker stats container1, container2 ...
# -- Ví dụ
docker status c-php
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
c4dd6ecd43b4 c-php 0.02% 20.74MiB / 1.952GiB 1.04% 2.86MB / 1.55MB 27.3MB / 0B 3
Docker tự khởi động Container nếu Container bị dừng
Triển khai một ứng dụng, container nào đó bạn muốn đảm bảo nó được Docker khởi động lại nếu bị dừng vì lý do nào đó thì khi tạo container bằng lệnh docker run cần thiết lập chính sách khởi động của container với tham số --restart=always
docker run -it --network www-net --name c-mysql -h mysql \
-v "/mycode/db":/var/lib/mysql1 -e MYSQL_ROOT_PASSWORD=abc123 \
--restart=always mysql
Tìm và thay đổi thông số, giới hạn CPU, RAM của Docker Container - Tham khảo
Kiểm tra thông tin và tình trạng sử dụng tài nguyên trên của Docker Container
docker stats
Trong đó:
- CONTAINER ID: là ID duy nhất của container
- NAME: Tên của container
- CPU %: Phần trăm sử dụng CPU
- MEM USAGE / LIMIT: Số lượng bộ nhớ sử dụng của container / Tổng bộ nhớ được phép sử dụng (Bộ nhớ của máy host cài docker)
- MEM %: Phần trăm sử dụng bộ nhớ
- NET I/O: Dữ liệu mạng I=INPUT dữ liệu đi vào container và O=OUTPUT là dữ liệu đi ra khỏi container.
- BLOCK I/O: Lượng dữ liệu mà container đã đọc và ghi từ các thiết bị khối (disk) trên máy host.
Bạn tham khảo cách dùng của lệnh docker stats ở đây
Đặt giới hạn CPU, bộ nhớ cho Docker Containers
# -- Set 1GB RAM và 1 core CPU cho container đã có - Runtime
docker update --memory "1g" --cpuset-cpus "1" <container_name>
# -- Set cho container lúc tạo
docker run -m 512m --memory-reservation=256m nginx
docker run --cpus=2 --cpu-shares=2000 nginx
# -- Hoặc với docker composer
service:
image: nginx
mem_limit: 512m
mem_reservation: 128M
cpus: 1
ports:
- "80:80"
Để kiểm tra lại chúng ta sử dụng lại lệnh docker stats

Chúng ta nghiên cứu kỹ hơn cách quản lý tài nguyên theo tài liệu của Docker ở đây.