Tản mạn docker
Docker
46
OCI
1
Podman
1
Buildah
1
Male avatar

certainlyT viết ngày 05/04/2020

Thời nay chắc có lẽ mọi người cũng đã nghe nhiều về con cá voi Docker.

Bài viết này không nhằm mục đích thương mại/PR cho Docker. Nó cũng không có mục đích giới thiệu căn bản về Docker mà chỉ đơn giản là lảm nhảm 1 vài trải nghiệm riêng của bản thân trong quá trình dùng Docker. Chửi có, 1 vài best practice cũng có.

1. Docker in general

Do not run as user root

(tô đỏ cho nó ngầu)

Nhiều bạn vẫn vô tư USER root trong Dockerfile

Hoặc nhiều khi đơn giản là dùng lại base image mà không biết base image đang chạy bằng user root

Cứ chờ đến khi mấy thằng Operation nó chửi và thuyết 1 bài dài về security risk :)

Giải pháp:

  • Nếu image của bạn bắt buộc phải chạy root (well, tôi cũng chả nghĩ ra lý do tại sao bạn lại cần quyền root nữa): tốt nhất là khỏi chạy container, cho nó thành 1 máy ảo riêng rồi giấu kĩ
  • Nếu không: đừng xài root, không có lý do gì để xài nó

Katacoda

Trang web khá thích hợp để học và vọc vạch Docker hay K8S. Ngoài ra thì cũng có 1 số course được thiết kế khá hay để học.

Phía backend là các server của google có cài sẵn Docker hay K8S tha hồ cho bạn vọc mà không cần cài K8S hay Docker lên laptop. Điều bạn chỉ cần là web browser. Khi bạn chạy 1 course trên katacoda, phía backend sẽ tạo 1 session docker/k8s cho bạn vọc.

Nhân nói đến kiến trúc này thì trong làng game cũng có công nghệ là Google Stadia. Túm lại là máy bạn chỉ cần web browser, google với số lượng server khủng của mình sẽ chạy game nặng cho bạn và truyền hình ảnh về cho client.

Mặc dù Google Stadia đang không thành công lắm (do ít game quá và yêu cầu đường truyền cao) nhưng mình nghĩ công nghệ này khá tiềm năng với sự lên ngôi hiện nay của cloud. Chờ thêm cái mạng từ vệ tinh của ông Musk nữa là ngon :D

2. Docker cho Windows (a.k.a hàng Linux xài trên Windows)

alt text

Cá nhân mình thì đã dùng docker ở cả Linux và Windows và mình không có trải nghiệm tốt với Docker for Windows tí nào. Docker for Windows phải chạy trên 1 con máy ảo trên Hyper-V chạy Linux như ở hình dưới

alt text

Điều này làm cho bạn không thể nào chạy cùng lúc Docker và VMware (VirtualBox)

Lý do: Hyper-V và VMware thuộc 2 dạng hypervisor khác nhau và không thể tồn tại cùng nhau. Hyper-V là hypervisor type 1 còn VMware là type 2.

alt text

Chi tiết hơn thì có thể đọc ở bài trên medium phân biệt type 1 và type 2

Additional khuyết điểm :

  • Chậm và nặng máy vãi chưởng (requirement cho Docker for Windows là 4Gb còn ở Linux là 2Gb)
  • Không có cơ chế để vào con máy ảo debug một cách dễ dàng (có 1 solution mà mình kiếm ra ở đây nhưng cũng là 1 cách trick)
  • Việc share ổ C và D tương đối khó khăn nếu công ty bạn không cấp quyền admin

Bên cạnh đó thì nó cũng có 1 số lợi ích:

  • cài docker-compose mặc định
  • có thể cài kubernetes dễ dàng
  • có UI ngon nghẻ
  • có Window container (mình cũng chưa thử và cũng chưa có nhu cầu thử :D )

Mà túm lại thì vẫn thấy không bằng chạy trên Linux. Thôi thì docker cũng xuất phát từ Linux mà ra ¯_(ツ)_/¯

3. Docker-compose

Đáng ra cái này nên được kèm chung thành default cho docker luôn. Mấy bạn học docker cũng nên học luôn cái này.

Viết ra 1 cái file như thế này rồi docker-compose up tốt hơn nhiều so với việc lọ mọ gõ docker run đến già. Nghe đồn phong phanh là có thằng dev gõ câu lệnh docker dài quá nên tự chế ra cái tool tên docker compose để tự xài. Sau docker thấy ngon quá mua lại luôn

Task càng yêu cầu nhiều sự can thiệp của con người, sai số càng cao. Bởi vậy nên cứ theo Infrastructure as Code

Hồi còn làm cho công ty startup, mình dùng docker-compose để deploy lên server và thấy nó ngon lành (không dùng Docker Swarm vì chỉ chạy trên 1 con server). Mình có viết một bài 3 phần về laradock chính là kinh nghiệm từ việc sử dụng và maintain cái docker-compose ấy

Tất nhiên là giờ qua xài k8s thì thấy nó chuối hơn hẳn (⌐■_■)

3. Alpine and Distroless

Optimize là điều nên làm cho Docker image rồi. Bạn không muốn có 1 cái image 1Gb để làm 1 chuyện mà image 10Mb cũng làm được

1 bài best practice mà mình luôn tâm đắc

Dockerfile best pratice

Có 1 bài về tối ưu Nodejs image trên Kipalog này của anh Minh Momen: Docker image in production - câu chuyện 1GB hay 100MB. 1.25Gb thành 150Mb là một cái gì đó đáng để tâm đấy ∠(^ー^)

Okay, alpine thì khá nhẹ rồi ~5Mb. Nhưng dạo gần đây mò mò tìm hiểu thì thấy có cái distroless base image của google.

Idea là image chỉ chứa application đang chạy của bạn. Không có bất kỳ thứ gì dư thừa khác. shell, yum, apt ... bỏ hết.

Đây là 1 ví dụ để build Java image

FROM openjdk:11-jdk-slim AS build-env
ADD . /app/examples
WORKDIR /app
RUN javac examples/*.java
RUN jar cfe main.jar examples.HelloJava examples/*.class 

FROM gcr.io/distroless/java:11
COPY --from=build-env /app /app
WORKDIR /app
CMD ["main.jar"]

Bạn chỉ đưa file jar vào trong distroless image và chạy, nhẹ như lông hồng.

Nghe bảo ngon nghẻ và nhẹ hơn alpine. Để bữa nào thử ( ・_・)ノ⌒●~*

4. Skopeo

Một bài toán thực tế ở công ty mình: xây dựng CI/CD cho Java Springboot app. Mỗi lần có Pull Request (PR), pipeline sẽ build image, xong đẩy lên một private registry.

1 pipeline khác lấy image trên private registry đó chạy thành 1 pod trên môi trường test để chạy integration test. Nếu integration test chạy ngon lành thì cho PR thành công.

Vấn đề phát sinh khi có quá nhiều image trên registry và cần 1 cách để xóa bớt những image cho các PR đó. Thông thường thì cách làm sẽ là gửi request lên registry api để xóa image nhưng mà vì mình lười cho nên là ngồi search google thôi.

Sau 1 hồi kiếm kiếm thì ra được Skopeo để tương tác với các registry khá tốt. Delete/Copy bằng một câu lệnh sướng phết 〈( ^.^)ノ

skopeo delete docker://localhost:5000/imagename:latest

1 điểm trừ duy nhất mà mình được biết là chưa hỗ trợ xóa image trên Jfrog Artifactory (vì thằng này api nó hơi khác 1 chút so với api của docker registry bình thường) cho nên là nếu công ty bạn đang dùng Artifactory để chứa các thứ thì cũng nên cân nhắc.

5. Docker có gì không vui?

Nếu bạn là người dùng Docker, bạn sẽ biết rằng có một chương trình nền (daemon process) được chạy dưới quyền root để phục vụ tất cả các lệnh Docker của bạn thông qua docker socket (var/run/docker.sock). Đây phải nói là 1 điểm mạnh nhưng cũng là 1 điểm yếu của Docker.

alt text

Một vài nhược điểm có thể kể ra là:

  • 1 process duy nhất có thể là "single point of failure"
  • Process đó sở hữu toàn bộ process con (là các container đang chạy)
  • Nếu có process fail, thì sẽ có các orphaned process (là các process mà thằng cha chạy xong rồi nhưng bản thân nó vẫn đang chạy)
  • Build image có thể gây ra các vấn đề về security
  • Tất cả các hoạt động của Docker phải được thực hiện bởi một người dùng có cùng quyền root

1 case study ở công ty mình:

Jenkins (là một container) chạy pipeline bao gồm việc build jar file + docker image cho application. Mình research tí và đề xuất giải pháp mount docker.sock cho thằng Jenkins. Operation team say déll <(`^´)>

Lý do:

  • việc mount docker socket đồng nghĩa với việc phải cho quyền jenkins user (chạy bên trong jenkins container).
  • khá là risky nếu xét về security. Nếu có người chiếm được Jenkins container thì họ cũng có quyền chơi với docker daemon và làm ảnh hưởng các container đang chạy trên k8s khác
  • và không cần thiết

A Docker image is a file, comprised of multiple layers, that is used to execute code in a Docker container. An image is essentially built from the instructions for a complete and executable version of an application, which relies on the host OS kernel

Túm lại là docker image chỉ là 1 file chứa các hướng dẫn để chạy container. Hãy kiếm 1 tool có thể tạo ra cái file như vậy và việc build image sẽ không cần docker socket nữa.

Okay good point. Mình research sâu thêm tí nữa.

Thực ra idea không dùng docker socket không mới. Ví dụ google có jib dùng để build image cho java application

Jib builds optimized Docker and OCI images for your Java applications without a Docker daemon - and without deep mastery of Docker best-practices

Ồ ra 1 solution để đưa Operation team rồi ( ´ ▽ ` )

Nhưng mà cuối cùng sau khi team Operation bàn bạc sao đó thì lại đồng ý cho mount docker socket 「(゚ペ)

Mà thôi cũng kiếm ra khái niệm OCI, thấy cũng nhiều nên mình đào sâu vô tí nữa

6. Open Container Initiative

OCI là gì?

Established in June 2015 by Docker and other leaders in the container industry, the OCI currently contains two specifications: the Runtime Specification (runtime-spec) and the Image Specification (image-spec). The Runtime Specification outlines how to run a “filesystem bundle” that is unpacked on disk. At a high-level an OCI implementation would download an OCI Image then unpack that image into an OCI Runtime filesystem bundle. At this point the OCI Runtime Bundle would be run by an OCI Runtime.

OCI gồm 2 phần chính:

  • image-spec: This specification defines an OCI Image, consisting of a manifest, an image index (optional), a set of filesystem layers, and a configuration.
  • runtime-spec: The Open Container Initiative Runtime Specification aims to specify the configuration, execution environment, and lifecycle of a container.

Các bạn có thể đọc thêm ở opencontainers.orgtrang github của OCI

Túm lại là OCI định nghĩa ra format của image được build và image đó được chạy thành container như thế nào.

-> OCI compatible: tức là image được build ra bởi phần mềm này sẽ chạy bình thường trên phần mêm khác.

Và kiếm ra 1 bài về docker và OCI runtime khá thú vị. Hóa ra docker có hàng đống thứ chạy đằng sau và runc là thư viện mà Docker đóng góp cho OCI

alt text

Điều này dẫn tới khám phá tiếp theo: podman & buildah

7. Podman & buildah

Podman là gì, nghe giống máy nghe nhạc?

Về cơ chế, podman cũng na ná Docker, kể cả câu lệnh. Khác biệt lớn nhất là Podman không chạy chương trình nền (daemon) mà liên hệ trực tiếp với Kernel qua thư viện runc

alt text

Podman sử dụng mô hình fork/execution truyền thống thay vì mô hình cliend-server của Docker

Vậy podman có gì thú vị mà mình phải đề cập ? Lý do nằm ở trên: cơ chế fork/execution này giúp tăng cường sờ-cu-rờ-ti cho container.

Nhờ vào đó, bạn có thể build và chạy container dưới một non-root user. Hơn nữa podman sẽ giúp bạn biết được user nào là người đã chạy container, giúp cho việc auditing dễ dàng hơn.

Chi tiết thì các bạn có thể đọc thêm bài này

Một sự thay thế không tồi cho việc build image mà không cần quyền root

Và đầu 2019, Podman cũng đã chạy được trên kubernetes

Mặc dù vậy thì vẫn có 1 vài nhược điểm của Podman như là rootless image

Buildah (giống buddha nhẩy)

Buildah thì tập trung vào việc build OCI image hơn là podman, dù vậy thì bạn sẽ thấy 2 thằng này thường được nhắc đến nhau như 1 cặp. Các câu lệnh của buildah sao chép lại các câu lệnh trong Dockerfile, cho phép build image không cần Dockerfile và không cần quyền root.

Ví dụ 1 file shell script để build image của buildah

#!/usr/bin/env bash -x

ctr1=$(buildah from "${1:-fedora}")

## Get all updates and install our minimal httpd server
buildah run "$ctr1" -- dnf update -y
buildah run "$ctr1" -- dnf install -y lighttpd

## Include some buildtime annotations
buildah config --annotation "com.example.build.host=$(uname -n)" "$ctr1"

## Run our server and expose the port
buildah config --cmd "/usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf" "$ctr1"
buildah config --port 80 "$ctr1"

## Commit this container to an image name
buildah commit "$ctr1" "${2:-$USER/lighttpd}"

buildah from = FROMtrong Dockerfile
buildah copy = COPY trong Dockerfile

Sức mạnh của buildah được thể hiện khá rõ trong file build trên. Trong Dockerfile, giá trị phải được hardcode. Tuy nhiên với buildah, bạn có thể đưa vào các biến để việc build image dễ dàng hơn

Buildah’s ultimate goal is to provide a lower-level coreutils interface to build images. The flexibility of building images without Dockerfiles allows for the integration of other scripting languages into the build process

Và buildah cũng chạy theo mô hình fork-exec và không cần chương trình nền (daemon) luôn.

Tìm hiểu sơ sơ chứ cũng chưa nhúng tay vào làm :p

Như vậy là qua tìm hiểu sơ sơ thì podman + buildah thành 1 cặp bài trùng có thể thay thế cho Docker. Buildah tập trung vào việc build image mạnh mẽ hơn việc Dockerfile, còn Podman giúp chạy container bảo mật hơn chút

Thôi bài cũng dài rồi, chủ yếu là than thở cái Docker, giới thiệu vài thứ lặt vặt đi kèm và thêm 2 công nghệ thú vị mới: podman và buildah. 1 vài link cho anh em để tham khảo nếu hứng thú dùng podman + buildah. Mình cũng chưa từng dùng nhưng daemonless cũng khá là thú vị:

https://boot2podman.github.io/assets/ContainersWithoutDocker.pdf
https://medium.com/@ganeshmani009/replacing-docker-with-podman-power-of-podman-cloudnweb-23cfb7541538
https://blog.giantswarm.io/building-container-images-with-podman-and-buildah/
https://developers.redhat.com/blog/2019/02/21/podman-and-buildah-for-docker-users/
https://jaxenter.com/build-containers-quickly-buildah-155839.html
https://developers.redhat.com/blog/2019/08/14/best-practices-for-running-buildah-in-a-container/
https://mkdev.me/en/posts/dockerless-part-3-moving-development-environment-to-containers-with-podman

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

certainlyT

4 bài viết.
12 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
Male avatar
6 1
Phần 1]: Giới thiệu và làm quen với laradock 1) Laradock là gì ? Tại sao nên dùng laradock ? Laradock = laravel + docker. Tức là dùng docker để t...
certainlyT viết hơn 1 năm trước
6 1
Male avatar
4 0
Phần 3]: Triển khai dự án laravel với laradock trên môi trường production Tiếp theo (Link), lần này ta sẽ triển khai một dự án laravel trên môi tr...
certainlyT viết hơn 1 năm trước
4 0
Male avatar
3 0
Phần 2]: Multi site trên laradock local Phần này ta sẽ tiếp tục những gì đã làm ở (Link). Ta sẽ triển khai thêm 2 project laravel: laravel2 với cấ...
certainlyT viết hơn 1 năm trước
3 0
Bài viết liên quan
White
10 0
Một trong những trường hợp build docker image là thừa hưởng từ một image mẹ Lấy một ví dụ sau: Dockefile FROM my_repo/my_image ENTRYPOINT ech...
Lơi Rệ viết gần 5 năm trước
10 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
4 bài viết.
12 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!