Basics of Docker
Một số định nghĩa cơ bản:
Docker image
Là file chứa tất cả các thông tin của chương trình, kể cả system, dependency,… được đóng gói vào.
Bạn có thể xem các image đã tạo trong folder /var/lib/docker/images
kết hợp sudo tree <path trên>
Cách diễn giải khác thì đây là một file bất biến - không thay đổi, chứa các source code, libraries, dependencies, tools và các files khác cần thiết cho một ứng dụng để chạy.
Docker container:
Là 1 môi trường tách biệt (như 1 container) được đặt trên máy ở 1 không gian riêng và không liên quan đến các chương trình khác.
Cách diễn giải khác là một run-time environment mà ở đó người dùng có thể chạy một ứng dụng độc lập. Những container này rất gọn nhẹ và cho phép bạn chạy ứng dụng trong đó rất nhanh chóng và dễ dàng.
Sự liên quan:
-
Image có thể tồn tại mà không cần container, trong khi container chạy thì cần có image đã tồn tại. Vì vậy, container phụ thuộc vào image và sử dụng nó để tạo ra run-time environment và chạy ứng dụng trên đó.
-
Cả image và container đều là thành phần quan trọng để tạo ra 1 running container. Docker image là cực kì quan trọng để chi phối và định hình 1 Docker container.
Cách RUN image trên UBUNTU
docker run ubuntu
//nếu chưa pull ubuntu image về thì sẽ pull rồi start, còn nếu pull rồi thì nó sẽ start container này luôn
=> nếu khi start mà thấy chưa có interact gì thì nó sẽ stop container lại luôn
docker ps
//xem list các tiến trình đang chạy của container hoặc các container đang chạy
docker ps -a
//xem các container đã dừng lại
docker run -it ubuntu
// start container với interaction mode và load ubuntu image lên trong cái container này
Các câu lệnh:
history
!2
//để output cmd thứ 2 trong list history
ls -1
//líst ds theo dạng dọc
ls -l
//list ds chi tiet
touch <tên file>
//lệnh tạo file
mkdir <tên thư mục>
//lệnh tạo thư mục
mv <tên file hoặc địa chỉ> <tên file hoặc địa chỉ>
//đổi tên hoặc di chuyển
cat <tên file>
more <tên file hoặc địa chỉ>
//xem nội dung theo từng page, bấm phím space để qua trang tiếp theo nhưng ko scroll up lên được, nhấn enter để chạy từng line để xem
less <tên file hoặc địa chỉ>
//
cat <tên file> > <tên file khác>
//copy nội dung file này vào file khác
cat <tên file> <tên file khác> > <tên combined file>
//combine nội dung 2 file vào file khác
dấu >
áp dụng cho hầu hết các câu lệnh
vd: echo hello > hello.txt
ls -l /etc > hello.txt
sẽ cho kết quả ra file hello.txt trên.
Trong Linux, mọi thứ đều ở duới dangj file, từ process, devices, hoặc địa chỉ thư mục đều là files
Cấu trúc Linux:
- /
- bin: chưa các file binaries, chương trình
- boot: các file liên quan booting
- dev: devices
- etc: editable text configuration, chứa file config
- home: thư mục của user
- root: chỉ có root mới vào được thư mục này
- lib: libary files như software library dependencies
- var: như biến, chứa các file được update thường xuyên như log,…
- proc: chứa các tiến trình đang running
Các bước để sử dụng Docker
- Cài đặt Docker
- Tạo 1 program và Tạo file plain text Dockerfile ghi hướng dẫn để đưa cho docker đóng gói ứng dụng thành 1 image. Image chứa tất cả mọi thứ để chương trình chạy.
IMAGE bao gồm:
- A cut-down OS
- Môi trường runtime (vd như Node, Python)
- File ứng dụng
- Thư viện thứ 3
- Biến môi trường => Sau khi có cái Image này, ta sẽ nói với Docker để start container Container như 1 process, nhưng là process đăc biệt vì nó có file system được cung cấp bởi Image. Ứng dụng của chúng ta sẽ được chạy trong cái process/container này.
Ok giờ chúng ta start docker. Thay vì chạy ứng dụng như bình thường, ta gọi Docker để chạy bên trong cái container nhé
docker run ..
Ví dụ sự khác nhau :
Để chạy 1 chương trình JS đơn giản, ta cần phải qua 4 bước:
- Start OS
- Cài Node
- Copy file ứng dụng
- Chạy
node app.js
Với docker, ta chỉ cần:
-
Bước 1:
- Vào thư mục project trên vscode
code .
Tạo fileDockerfile
không ext, và input các thông tin sau:
- Vào thư mục project trên vscode
FROM node:alpine
Chọn image node trên trang docker hub và : distribution của linux, ở đây chọn alpine vì nó nhẹ nhất .
COPY . /app
copy tất cả file execute vào thư mục app tạo mới, vào rồi copy vào trong image
hoặc có thể hiểu là trong cái image có file system, và chúng ta tạo thư mục app bên trong file system đó, trong thư mục app chứa tất cả các file của program.
File requirements.txt chứa các thư viện mà chương trình cần. Cần COPY trước khi RUN các cài đặt trong Dockerfile. VD của file:
tornado==6.1
. Với Pycharm thì ta có thể dùng Tools=>Sync Python Requirement để tự động generate.
WORKDIR /app
tạo đường dẫn rút gọn
CMD node /app.js
câu lệnh chạy ứng dụng, để docker biết mà chạy câu nào khi run
- Bước 2:
Ta nói docker đóng gói úng dụng thành image
docker build -t hello-docker .
trong đó, dấu . chỉ cho docker biết chỗ nào chứa Dockerfile hello-docker là tên repos docker mình tự tạo để quản lý
Để xem có bao nhiêu docker đang chạy:
docker image ls
kết quả câu lệnh có cột SIZE chỉ size của OS (alpine) + ứng dụng + node
- Bước 3:
Chạy thử docker image
docker run hello-docker
Đây là câu run cơ bản, ta có thể chạy ở thư mục nào cũng được, vì image đã chứa mọi thứ cần.
Hầu hết các docker run dùng cú pháp chuẩn này:
Cách 1:
docker run -d -p 80:8888 shorten-link
Với 8888 ở đây là listen port của program trên container tại đây https://github.com/tuyen-nnt/shortenLink/
Với 80 là port trên máy host của mình,
-d
là chạy ngầm.
Sau khi docker run thì ta test container bằng cách chạy câu lệnh:
docker exec -it <CONTAINER ID> bash
Trả về:
root@05b418a61ca3:/app# ls
ls
để list ra các file trong docker image, có thể check xem bước COPY đã đúng những file mình cần để chạy chương trình chưa?
Để test wep app trên browser, ta dùng địa chỉ ip của máy:port máy host (expose) và thêm /đường dẫn như cài đặt.
Cách 2:
Không cần port mà dùng luôn localhost, nghĩa là user bên ngoài chỉ cần dùng IP gateway:port của chương trình là được:
docker run -d --net=host shorten-link
Tuy nhiên nên hạn chế cách này, vì sẽ khiến conflict với các chương trình khác nếu chẳng may host mình cũng dùng port 8888 này ở chương trình đâu đó, vì mình không quyết định và control được port map (interface) như cách 1 để tùy chỉnh. Còn để host kiểu này khó biết được.
- Bước 4 Publish lên docker hub: hub.docker.com
Khi ở máy khác, ta muốn pull image về chạy:
-
Bước 1: Kiểm tra version docker, nếu chưa download thì chạy lệnh install
docker vesion
-
Bước 2: Kéo image về
docker pull senrie/hello-docker
Kiểm tra lại = cách:
docker image ls
- Bước 3:
Chạy chương trình trên machine
docker run senrie/hello-docker
Về PORTS trong Docker
Ta có thể xem các container đã build bằng lệnh docker ps
: danh sách container đang chạy, và lệnh docker ps -a
: tất cả container đã build.
Ta thấy có cột PORTS, ví dụ:
0.0.0.0:80->8888/tcp, :::8888->8888/tcp
Mình sẽ giải thích từng chỉ số:
- 0.0.0.0: nghĩa là có thể dùng tất cả các IP của máy (IP card mạng LAN, IP wifi,.. có thể check bằng
ifconfig
) để làm gateway cho bên ngoài truy cập vào thông qua port cụ thể bên dưới. - 80 (layer ngoài): là port của máy host expose cho bên ngoài dùng để truy cập vào, như cánh cổng mở ra
- 8888 (layer trong): là listen port của chương trình trên container trong máy host của chúng ta.
Port 80 sẽ được setup trên tất cả các gateway và centralize lại để link với container có port 8888. Nghĩa là ta dùng IP gateway:80 thì sẽ tiếp cận được đến chương trình container.
Để check xem máy chúng ta đang chạy các port nào tránh conflict, ta dùng lệnh:
sudo netstat -plunt
Xem qua về Docker run để hiểu hơn: https://docs.docker.com/engine/reference/commandline/run/
Xem cấu hình
Các cmd thường dùng:
docker inspect <containerID>
: xem các gateway, ip, network,… của container để biết nó đang xài network nào- Nếu cài port khi run thì network là “bridge” (khi netstat sẽ ra
docker-proxy
) - Nếu dùng –net=host thì network là “host”
- …
- Nếu cài port khi run thì network là “bridge” (khi netstat sẽ ra
-
wrk -t4 -c400 -d30s <url>
: xem perform mance của web (tham khảo thêm tại https://github.com/wg/wrk)Các bước fix bugs
- Bước 1: Xác định xem lỗi gì (dùng curl, Postman hoặc F12)
- Bước 2: Coi log. Ví dụ:
docker logs -f $(docker ps | grep "83->" | awk '{print $1}')
Thêm tag
-f
để xem log real time không cần in hết log. - Bước 3: Debug
- Dynamic Analysis: dùng break point hoặc print ra console,… => Cách này áp dụng tốt cho các trường hợp phức tạp và đơn giản cũng ok nếu đoán được code chỗ nào lỗi.
- Static Analysis: đọc code chay (khi không biết chỗ nào run function đó, thường thì trong hướng đối tượng hay gặp phải)
Comments