Docker là gì?
Triết lí: Build one run anywhere
- Docker là nền tảng dùng để đóng gói, phân phối và triển khai application
- Container là môi trường ảo hóa
độc lập, hoàn chỉnh, dễ thay thế: chứa chương trình và các gói bổ sung cho chương trình chính
- Độc lập: chương trìn bên trong container không thể biết và truy cập đến các chương trình bên ngoài
- Hoàn chỉnh: container chứa đầy đủ những gì application cần
- Dễ thay thế: Container thường nhẹ nên dễ xóa cũ, tạo mới. Không mất thời gian. Khả năng scaling cao
Tại sao lại sử dụng Container
- Khi phát triển một ứng dụng, thì ta cần phải triển khai trên nhiều môi trường khác nhau
- Development
- QA
- Production
- Những môi trường ở những điều kiện hoàn toàn khác nhau nên nếu môi trường development chạy ổn thì chưa chắc những môi trường còn lại cũng vận hành trơn tru và ổn định.
Docker context
-
Chuyện là mình có 1 server vps, mình remote vào docker ps, docker images,.. docker logs -f nhiều quá mình lười, mà máy local mình setup sẵn đủ đồ chơi (như
lazydocker), xài tiện hơn, nên mình muốn chạy mấy lệnh docker trên local nhưng thao tác trên con vps kia thì phải làm sao? Docker context sẽ giúp mình làm việc này -
Tạo
contextmới tên vps, kết nối qua ssh tới con remote server với- username: user
- ip: remote-server-ip
- nhập pass ssh khi được hỏi
docker context create vps --docker "host=ssh://user@remote-server-ip"-
Chuyển qua lại giữa các context
- Chuyển sang context vps
Terminal window docker context use vps- Chuyển về context mặc định (local)
Terminal window docker context use default -
Liệt kê các context
❯ docker context lsNAME DESCRIPTION DOCKER ENDPOINT ERRORdefault Current DOCKER_HOST based configuration unix:///var/run/docker.sockfpt * ssh://fptfpt-server ssh://hoang@123.456.789.000-
Ở đây mình có 3 context
- default: context mặc định, thao tác trên máy local
- fpt: context kết nối tới con server fpt (alias là fpt, này config trong
~/.ssh/configrồi) - fpt-server: context kết nối tới con server (username: hoang, ip: 123.456.789.000)
-
Đây là alias trong file
~/.ssh/configcủa mình, bạn có thể tham khảo để cấu hình ssh cho tiện nhé
❯ cat ~/.ssh/configHost * ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 600
Host fpt HostName 123.456.789.000 User root IdentityFile ~/.ssh/id_gitlab_lcaohoanq
Host w520 HostName 192.168.88.155 User lcaohoanq Port 1604 IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 30 ServerAliveCountMax 3- Xóa context
docker context rm vps- Xem chi tiết context hiện tại
docker context inspect- Xem help của docker context
❯ docker context --helpUsage: docker context COMMAND
Manage contexts
Commands: create Create a context export Export a context to a tar archive FILE or a tar stream on STDOUT. import Import a context from a tar or zip file inspect Display detailed information on one or more contexts ls List contexts rm Remove one or more contexts show Print the name of the current context update Update a context use Set the current docker context
Run 'docker context COMMAND --help' for more information on a command.Hãy cẩn thận khi thao tác với context
Mình vừa có một phen hú hồn khi rãnh tay prune (container, image) mình tưởng là trên máy mình, nhưng mình chợt vô các api, web đột nhiên tắt hết, mình mới tá hỏa chạy lại lệnh docker ps thì thấy là đang ở context remote server, và lệnh docker rm -f $(docker ps -a -q) đã xóa tất cả container trên con server đó, may mà mình đã có workflow deploy tự động + mount volume nên chỉ mất thời gian deploy lại chứ không mất dữ liệu gì cả, coi như là test disaster recovery miễn phí :)))

Tưởng tưởng chừng này proxy bị xóa hết, và phải tạo lại từ đầu, quá sợ :)
Vấn đề thật sự nằm ở docker context
mình nhầm giữa:
default -> localfpt -> ssh://fpt```****
- Docker CLI **không hiển thị context rõ trong terminal** nên rất dễ nhầm.
- Có thể devops khác sẽ không dùng **docker context**, mà sẽ ssh vào server rồi thao tác trực tiếp cho an toàn, nhưng nếu dùng **docker context** thì sẽ tiện hơn rất nhiều, vì tận dụng được setup, CLI tools ở máy local, nên mình nghĩ là docker nên cải thiện phần này để tránh nhầm lẫn, có thể hiển thị context hiện tại ở prompt hoặc ít nhất là highlight khi đang ở context remote server để tránh nhầm lẫn, hoặc mình tự custom prompt trong terminal để hiển thị context hiện tại cũng được, nhưng mà nếu docker có sẵn thì tốt hơn nhiều rồi :)))
---
# Docker ps
Ps (Process): liệt kê các container đang chạy
```zshdocker psKết quả
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESed22890229b4 redpandadata/redpanda:latest "/entrypoint.sh redp…" 13 days ago Up 9 minutes (healthy) 0.0.0.0:9092-9093->9092-9093/tcp, [::]:9092-9093->9092-9093/tcp, 8081-8082/tcp, 0.0.0.0:9644->9644/tcp, [::]:9644->9644/tcp redpanda1b3f04a6ea11 postgres:17.4 "docker-entrypoint.s…" 4 weeks ago Up 9 minutes (healthy) 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp postgres98d8d145d49d redis:7.2.3 "docker-entrypoint.s…" 4 weeks ago Up 9 minutes (healthy) 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp redis-container7ed17a84f912 dpage/pgadmin4 "/entrypoint.sh" 4 weeks ago Up 9 minutes 443/tcp, 0.0.0.0:5050->80/tcp, [::]:5050->80/tcp pgadmin- Thêm
-ađể liệt kê tất cả container (kể cả dừng)
docker ps -aKết quả
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESdd51ff8cd1c7 proxmox_ui-app "/usr/local/bin/dock…" 16 hours ago Exited (1) 9 hours ago proxmox-lxc-apped22890229b4 redpandadata/redpanda:latest "/entrypoint.sh redp…" 13 days ago Up 9 minutes (healthy) 0.0.0.0:9092-9093->9092-9093/tcp, [::]:9092-9093->9092-9093/tcp, 8081-8082/tcp, 0.0.0.0:9644->9644/tcp, [::]:9644->9644/tcp redpandadbe274fc116b postgres:16-alpine "docker-entrypoint.s…" 2 weeks ago Exited (0) 2 weeks ago crazy_brown30f7215138cf amir20/dozzle:latest "/dozzle" 4 weeks ago Exited (0) 4 weeks ago nice_easley00b2b3e5370c job-hunter-api "java -jar app.jar" 4 weeks ago Exited (143) 4 weeks ago job_hunter_backend2dc1af9953fa phpmyadmin:5 "/docker-entrypoint.…" 4 weeks ago Exited (0) 3 weeks ago phpmyadmin_ui34ed0964f7d4 mysql:8.0 "docker-entrypoint.s…" 4 weeks ago Exited (0) 3 weeks ago mysql1b3f04a6ea11 postgres:17.4 "docker-entrypoint.s…" 4 weeks ago Up 9 minutes (healthy) 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp postgres98d8d145d49d redis:7.2.3 "docker-entrypoint.s…" 4 weeks ago Up 9 minutes (healthy) 0.0.0.0:6379->6379/tcp, [::]:6379->6379/tcp redis-container7ed17a84f912 dpage/pgadmin4 "/entrypoint.sh" 4 weeks ago Up 9 minutes 443/tcp, 0.0.0.0:5050->80/tcp, [::]:5050->80/tcp pgadmin350dc94561e0 getmeili/meilisearch:v1.29.0 "tini -- /bin/sh -c …" 4 weeks ago Exited (143) 4 weeks ago bit-learning-be-meilisearch-1-
Thêm
--formatđể định dạng output theo ý muốn, thay vì loc cột bằngawk-
zsh docker ps -a | awk '{print $1, $2, $NF}': lấy cột CONTAINER, IMAGE, NAMES (nhưng CONTAINER ID có khoảng trắng) -
zsh docker ps -a | awk 'NR==1 {print "CONTAINER_ID IMAGE NAME"} NR>1 {print $1, $2, $NF}: in ra header cho đẹp
-
Cách đơn giản hơn với --format
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Status}}"Kết quả
❯ docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Names}}"
CONTAINER ID IMAGE NAMESdd51ff8cd1c7 proxmox_ui-app proxmox-lxc-apped22890229b4 redpandadata/redpanda:latest redpandadbe274fc116b postgres:16-alpine crazy_brown30f7215138cf amir20/dozzle:latest nice_easley00b2b3e5370c job-hunter-api job_hunter_backend2dc1af9953fa phpmyadmin:5 phpmyadmin_ui34ed0964f7d4 mysql:8.0 mysql1b3f04a6ea11 postgres:17.4 postgres98d8d145d49d redis:7.2.3 redis-container7ed17a84f912 dpage/pgadmin4 pgadmin350dc94561e0 getmeili/meilisearch:v1.29.0 bit-learning-be-meilisearch-1- Thay vì thủ công lọc bằng
grep, ta có thể dùng--filterđể lọc kết quả,statusnằm trong các options sau:- created
- running
- paused
- restarting
- removing
- exited
- dead
docker ps --filter "status=exited"Kết quả
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESdd51ff8cd1c7 proxmox_ui-app "/usr/local/bin/dock…" 16 hours ago Exited (1) 9 hours ago proxmox-lxc-appdbe274fc116b postgres:16-alpine "docker-entrypoint.s…" 2 weeks ago Exited (0) 2 weeks ago crazy_brown30f7215138cf amir20/dozzle:latest "/dozzle" 4 weeks ago Exited (0) 4 weeks ago nice_easley00b2b3e5370c job-hunter-api "java -jar app.jar" 4 weeks ago Exited (143) 4 weeks ago job_hunter_backend2dc1af9953fa phpmyadmin:5 "/docker-entrypoint.…" 4 weeks ago Exited (0) 3 weeks ago phpmyadmin_ui34ed0964f7d4 mysql:8.0 "docker-entrypoint.s…" 4 weeks ago Exited (0) 3 weeks ago mysql350dc94561e0 getmeili/meilisearch:v1.29.0 "tini -- /bin/sh -c …" 4 weeks ago Exited (143) 4 weeks ago bit-learning-be-meilisearch-1Dừng container theo điều kiện lọc
docker ps --filter "status=running" --format "{{.ID}}" | xargs docker stop- Giải thích:
- Lấy ID của các container đang chạy
- Dùng
xargsđể truyền từng ID vào lệnh docker stop
Dừng tất cả container đang chạy
docker stop $(docker ps -a -q)Bind mount và name volume
Bind mount là gì?
Bind mount = mount thẳng một thư mục của host vào container.
volumes: - ./data:/dataNghĩa là
Server/home/app/data ↓Container/dataContainer ghi gì vào /data thì file thật nằm trên host.
Bạn SSH vào server là thấy ngay.
Ví dụ:
ls data/Ưu điểm
Dễ debug, xem log trực tiếp
cat data/config.jsonBackup dễ
tar czf backup.tar.gz data/Migrate server dễ, copy folder data sang server mới, chạy lại docker là xong
scp -r data new-serverNhược điểm
Phụ thuộc filesystem host, nếu deploy sang server khác thì đảm bảo folder đó tồn tại và có quyền truy cập vậy nên không portable
Name volume là gì?
Name volume = Docker quản lý storage cho bạn.
volumes: - redis-data:/datacuối file
volumes: redis-data:Data thật đang nằm ở
/var/lib/docker/volumes/redis-data/_dataDocker quản lí, bạn không cần biết path thật của nó, chỉ cần biết tên volume là được, docker sẽ tự mount vào container, bạn có thể dùng lệnh docker volume để quản lý volume
Ưu điểm
- Portable hơn, compose chạy ở đâu cũng được, docker sẽ tự tạo volume và mount vào container, không cần lo về path hay quyền truy cập như bind mount
- An toàn hơn khi deploy, bạn có thể
docker compose downdocker compose updata vẫn còn nguyên, không bị xóa mất như bind mount nếu bạn xóa folder data trên host, nhưng với name volume thì docker sẽ giữ lại dữ liệu trong volume, trừ khi bạn xóa volume đó đi bằng lệnh docker volume rm <volume-name>
Nhược điểm
- Khó debbg, để xem log hay backup dữ liệu thì phải dùng lệnh
docker volumeđể truy cập vào volume, không thể truy cập trực tiếp như bind mount
docker volume inspect redis-data- Backup khó hơn, phải dùng lệnh
docker runđể tạo một container tạm thời mount volume đó vào rồi backup từ container đó, không thể backup trực tiếp như bind mount
docker run --rm \ -v redis-data:/data \ -v $(pwd):/backup \ alpine tar czf /backup/redis.tar.gz /dataKhi nào nên dùng cái nào?
Đối với bind mount, nên dùng cho môi trường development, khi bạn cần debug, xem log trực tiếp, backup dễ dàng, migrate server nhanh chóng, nhưng không nên dùng cho production vì nó phụ thuộc vào filesystem host, không portable, dễ bị xóa mất dữ liệu nếu xóa folder trên host
Bind mount thường dùng cho
configcertlogsdev environmentVì tweak config nhanh
Name volume thường dùng cho
databasequeuecachestorage engineNhững ứng dụng hay dùng
- Đồ chơi sẽ để ở đây, rất cảm ơn bác ChristianLempa đã chia sẻ bộ đồ chơi khủng long này: https://github.com/lcaohoanq/boilerplates
- Đây là những app mình hay xài nhất
- postgres: (https://hub.docker.com/_/postgres)
- Nhớ để ý password nhé, được mount ra file secret.postgres_password.txt và đọc ngược vào runtime container
- docker compose up -d bla bla bla, health check -> healthy -> ngon chạy
- giờ mình muốn tạo nhanh một db tên bit_learning, nếu gà: ê launch tiếp cái container dbgate nữa =)))) để tạo bằng ui, vì sao mình không chọn pgadmin mà dbgate vì một là nó nhẹ hơn, 2 là nó hỗ trợ được nhiều loại db thay vì chỉ mỗi postgres
- cánh nhanh nhất exec vào shell tạo luôn
-
docker exec -it <tìm id của postgres bằng docker ps> bash
-
Terminal window root@e620c11bfca0:/# lsbin dev etc lib media opt root sbin sys usrboot docker-entrypoint-initdb.d home lib64 mnt proc run srv tmp varroot@e620c11bfca0:/# psql -U postgrespsql (17.4 (Debian 17.4-1.pgdg120+2))Type "help" for help.postgres=# SHOW DATABASES;postgres=# CREATE DATABASE bit_learning;CREATE DATABASEpostgres=# \lList of databasesName | Owner | Encoding | Locale Provider | Collate | Ctype | Locale | ICU Rules | Access privileges--------------+----------+----------+-----------------+------------+------------+--------+-----------+-----------------------bit_learning | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | |postgres | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | |template0 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/postgres +| | | | | | | | postgres=CTc/postgrestemplate1 | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | =c/postgres +| | | | | | | | postgres=CTc/postgres(4 rows) -
\l(suyệt e lờ) để SHOW DATABASE nhóe
-