Docker: Chưa biết gì đến biết dùng ( Phần 4 - Một số trick tối ưu và lưu ý )
Bài đăng này đã không được cập nhật trong 5 năm
1. Mở đầu
- Chào các bạn, sau khi đi qua ba phần đầu của series:
Docker - Chưa biết gì đến biết dùng
- Chúng ta đã tìm hiểu vai trò, cách sử dụng
Dockerfilke
&&docker-compose.yml
để ứng dụngDocker
vào trong dự án.
-
Hôm nay, chúng ta sẽ tiếp tục tìm hiểu một số cách để
tối ưu
công cụ này nhé ! -
Bài viết tiếp tục dựa trên
Rails framework
để tìm hiểu, nhưng tác giả sẽ cố gắng để viết tổng quát vấn đề.
2. Docker-compose up
-
Sau khi chúng ta gõ docker-compose up thì
-
Câu lệnh này sẽ
pull
/build
tất cả cả cácimages
mà chúng ta đã định nghĩa -
Trong trường hợp máy đã
có sẵn
image thì sẽ được skip bước này -
Tiếp theo là
run image
vàcreate container
. -
Rồi đính kèm chúng với các
service
tương ứng (Luôn nhớ rằng mỗicontainer
ứng với một máy ảo) -
Câu lệnh này sẽ tổng hợp
logs
của tất cả cáccontainer
và hiển thị lênTerminal
-
Ở đây có
mysql service
vàapp service
nên cólogs
của 2 bác này, màu hiển thị cũng khác nhau cho chúng ta dễ phân biệt. -
Khi muốn tắt
service
thì nhấn tổ hợp phímCtrl + C
-
Nếu như bạn dùng
docker-compose up -d
thì cáccontainers
sẽ chạy ngầm, màn hìnhTerminal
sẽ không hiển thịlogs
-
-
Với cách triển khai này thì có chút nhược điểm như sau:
-
Như bạn thấy ở trên, khi
Ctrl + C
thì sẽ tắt tất cảservice
, -
Khi
docker-compose up
thì lại bật tất cả chúng lên. -
Cứ tắt bật, tắt bật tất cả
service
liên tục như thế, trong project này chỉ có 2service
nên có vẻ chưa hề hấn gì nhưng nếu số lượngservice
lớn hơn (ví dụmysql
+redis
+nginx
....) thì cũng mất kha khá thời gian đấy. -
Hơn nữa, khi chúng ta debug code trên Terminal, kiểu như thế này
-
Thì
docker-compose up
sẽ không dừng hiển thịlogs
để chúng takiểm tra giá trị
của các biến chẳng hạn, -
Mà bỏ qua một cách lạnh lùng, như thế này.
-
Bởi vì
docker-compose up
hiển thịlogs
tổng hợp của tất cảservice
-
Không vì một
service
nào mà dừng lại cả, như vậy là chúng ta khôngdebug
được.
-
-> Giải pháp là gì ?
-
Thay vì bật tất cả
containers
lên cùng một lúc -
Chúng ta sẽ bật các
background containers
lên trước (ví dụ: mysql, redis ...) -
Sau đó mới bật
main container
(ví dụ: app). -
Khi stop thì ta chỉ stop
main container
thôi, cácbackground containers
vẫn chạy ngầm bên dưới. -
Câu lệnh
-
Start background container( chỉ 1 lần khi mới mở máy tính lên )
docker-compose up -d mysql docker-compose up -d redis docker-compose up -d woker
-
Start main container
docker-compose run --rm -p 3000:3000 app rails s
-> Với cách này chúng ta sẽ luôn có
background service already running
, thời gian khởi động ứng dụng sẽ giảm xuống.->
docker-compose run
sẽ dừng để bạn có thể debug,--rm
sẽ xóa chính container này đi khi bạn stop nó. -
3. Makefile
- Phải công nhận là gõ những dòng
docker-compose up -d ...
nhiều như vậy thật là mệt.
-
Chưa kể
docker-compose build
,up
rồidown
,run
... -
Vậy thì hãy dùng Makefile, công dụng của nó thì có nhiều hơn nhưng ở đây mình chỉ ứng dụng nôm na giống như Git alias vậy, không cần phải ghi nhớ và gõ nhiều câu lệnh.
-
Thay vì phải gõ từng câu lệnh một
docker-compose up -d mysql docker-compose up -d redis docker-compose up -d worker
hoặc ngắn hơn
docker-compose up -d mysql redis worker
thì hãy viết vào trong Makefile:
up: docker-compose up -d mysql redis worker
và
dev: docker-compose run --rm -p 3000:3000 app rails s
-
Khi đó, trên Terminal gõ
make up
để start cácbackground containers
, sau đó gõmake dev
để startmain container
-
Mình có push code mẫu lên GitHub
-
Hơn nữa, khi có một member mới vào dự án và chưa rõ về Docker (có thể là member của team front end chẳng hạn), khi support setup project, bạn chỉ cần hướng dẫn.
- Chạy
make up
để bật các tiến trình nền. - Chạy
make dev
để start project. - Chạy
make test
để test code trước khi gửi pull request.
- Chạy
Mà bản thân họ không cần phải có quá nhiều kiến thức về Docker, khá là tiện lợi phải không
3. Depends_on && links
- Ở một số hướng dẫn, chúng ta có thể nhìn thấy sử dụng depends_on & links, ví dụ:
app:
build: .
container_name: app
depends_on:
- mysql
- redis
hoặc
app:
build: .
container_name: app
links:
- mysql
- redis
-
depends_on
vàlinks
được dùng để thể hiện sự phụ thuộc giữa cácservice
, nó tạo ra các hành vi:docker-compose up
sẽ khởi động cácservice
theo thứ tự phụ thuộc, ở đây sẽ là khởi độngmysql
vàredis
trước.docker-compose up app
- tức là khi bạn chỉ khởi động 1 service đơn lẻ thì servicemysql
vàredis
vẫn sẽ được khởi động.
-
Sự khác nhau giữa hai đồng chí này, thậm chí links cuối cùng có thể được gỡ bỏ, thay vào đó các service nằm trong cùng một network thì có thể tự tìm thấy nhau.
-
Thì đấy, bạn có thể giải quyết vấn đề này bằng cách sử dụng
depends_on
nhưng nhược điểm thì đã nên ở trên, cứ bật lên tắt xuống mất khá nhiều thời gian, trong thực tếservice mysql
có thể mất tới gần 20s để khởi động. -
Thậm chí khi
mysql container
đã chạy sẵn mà bạnrun container app
lên thì Docker vẫn tạo mới mộtmysql container
nữa chứ không sử dụngmysql container
đó.
4. CMD && entrypoint
5. Layers và images
-
Docker image
được xây dựng dựa trên cáclayers
xếp chồng, giống như việc bạn xếp nhiều viên gạch chồng lên nhau vậy. -
Cùng xem cách Docker build image
-
mysql uses an image, skipping
: Container mysql sử dụng image có sẵn bên không cần build image nữa ->skipping
-
Building app
: Bắt đầu build image chocontainer app
. -
Step 1/15
,Step 2/15
,Step 3/15
... Từng câu lệnh trongDockerfile
sẽ được thực thi và sẽ tạo ra cáclayers
tương ứng.Nếu câu lệnh trước đó đã được thực thi và tạo
layer
thì Docker sẽ sử dụnglayer
cũ đó chứ không tạolayer
mới nữa, giúpgiảm thời gian
build image và nếu ở mộtlayer
có sự thay đổi thì kể từ layer đó trở về sau, tất cả sẽ được build lại.
-
-
Dùng
docker images -a
để kiểm ra danh sách các images nhé.
Oài, sao nhiều
none image
vậy ? Chúng là gì, sao dung lượng của chúng lớn vậy ? Nó sẽ tiêu thụ nhiều không gian ổ cứng à ?
- Thực ra
none image
chính là nhữnglayers
, hãy xem cách Docker pull images về như thế nào.
-
Cũng tương tự như khi chúng ta
build image
vậy, từnglayer
được xây dựng theo mô hình cha con, sinh sau đẻ muộn hơn thì làlayer con
, kế thừa từlayer cha
, tất cả đều được đặt tên là<none>
như bức ảnh ở trên, đếnlayer
cuối cùng thì mới đầy đủimage
của chúng ta và đặt tên chính xác. Cùng xem kích thước cáclayers
tăng dần kìa.-
Dòng
---> Using cache
xuất hiện mỗi khi bạnbuild image
chính là tái sử dụng cáclayers
. Nhữnglayers
mà không được tái sử dụng nữa được gọi làdangling images
, tạm dịch là nhữngimage
lơ lửng -> nó không trỏ tớiimages
nào cả. -
Ủa lạ hây, phải gọi mà
dangling layers
mới đúng chứ nhỉ ? Các tài liệu mà mình tham khảo chưa thấy có khái niệm dangling layers, chỉ có dangling images thôi. Mà câu lệnhdocker images -a
cũng trả về cả danh sáchimages
&& danh sáchlayers
nữa,-a
là viết tắt củaall
, thếlayers
vớiimages
làsêm sêm
nhau à. Cũng có thể hiểu như vậy, vì nếu trongDockerfile
, ta xóa bỏ đi vài dòng cuối, thìlayers
ngoài cùng đó trở thànhimages
còn gì
-
6. Một vài lưu ý nhỏ
Có một chút lưu ý khi sử dụng Docker như sau:
-
Quy định
phiên bản
của image chi tiết nhất có thể.-
Nếu bạn define
services: mysql: image: mysql container_name: mysql
thì mặc định, Docker sẽ pull
image mysql phiên bản mới nhất về
, ở thời điểm bạn viếtDockerfile
thì có thể mysql phiên bản mới nhất là5.7
nhưng đến khi người khác settup project thì có thể nó đã lên tới phiên bản8.0
-
Và ở giữa phiên bản có những sự thay đổi nhất định, có thể một
hàm, phương thức
nào đó hoạt động tốt ởmysql 5.7
nhưng không hoạt động tốt ởmysql 8.0
, ví dụ vậy. Như thế sẽ dễ phát sinh bug tiềm ẩn và cũng vi phạm tính đồng nhất môi trường màDocker
lấy làm tôn chỉ.
-
-
Ở Dockerfile, các phần dễ thay đổi thì thực hiện về sau.
-
Như lý thuyết về phần
layer
đã nhắc tới, nếu ở mộtlayer
có sự thay đổi thì kể từ layer đó trở về sau, tất cả sẽ được build lại -
Do vậy, những câu lệnh nào có khả năng thay đôỉ cao, bạn hãy đặt nó xuống dưới cùng.
-
-
Hãy xóa bỏ những
layers
không cần thiết-
Những
dangling images
không còn hữu ích nữa, chúng cũng không được Docker tự động xóa, mà chúng ta sẽ xóa thủ công nó đi để giải phóng bộ nhớ. Cũng chưa rõ các phiên bản sau này, Docker có tự động xử lý việc này không -
Hôm nay là 24/03/2019, Dương lịch, Linux OS
docker -v -->> Docker version 18.09.0, build 4d60db4
- Danh sách images:
- Chỉnh sửa nội dung 1 dòng lệnh gần cuối của
Dockerfile
(giữ nguyên số lượng câu lệnh) và tiến hànhbuild image
thì thấy từ vị trí thay đổi trở đi không còn được sử dụngcache
nữa
- Kiểm danh sách images thì thấy số lượng
none images
tăng lên -> Oh, đúng rồi ^_^
- Kiểm tra danh sách image "lơ lửng", xóa nó đi và kiểm tra lại
Danh sách
none images
chỉ hiển thị id củalayer
tại vị trí mà bạn thay đổi, khi xóa nó thì sẽ xóa tất cảlayers con
đi kèm.Ngoài ra có thể tham khảo lệnh
docker system prune
để dọn dẹp choDocker
-
5. Updating ...
- Trong phần 5 chúng ta sẽ cùng tìm hiểu về deploy with Docker nhé (bao gồm cấu hình nginx, sử dụng haproxy ....) Mời mọi người đón đọc.
All rights reserved