Xây dựng Container Images với Podman và Buildah

cloudFun

building-container-images-widh-podman-and-buildah.jpg


Đây là bài thứ hai trong một loạt các bài đăng trên blog về việc xây dựng Container Images. Loạt bài bắt đầu với Tương lai của việc xây dựng container image đã thảo luận việc xây dựng images thay đổi như thế nào kể từ khi Docker ra mắt lần đầu tiên và cách khắc phục một số hạn chế của việc sử dụng Dockerfiles. Bài đăng này tập trung vào Podman và Buildah và trong các bài đăng trong tương lai, sẽ thử nghiệm các phương pháp mới khác trong lĩnh vực này.
PodmanBuildah là hai công cụ khá gần đây đã xuất hiện để hỗ trợ xây dựng image container. Chúng là các công cụ bổ sung của Kho lưu trữ mở cho Công cụ Container và xuất phát từ nhiệm vụ lấy daemon Docker từ workflow của container của Red Hat. Tại sao cần đến hai công cụ, và mỗi công cụ mang lại trải nghiệm xây dựng image container như thế nào? Hãy bắt đầu với Podman.

Podman
Mục đích của Podman vượt ra ngoài mục tiêu xây dựng image container, nhưng nó thường được thảo luận cùng với Buildah và được xem xét ở đây vì nó có đóng góp để thực hiện việc xây dựng image container.

Bản dựng Daemonless
Podman cố gắng tái tạo toàn bộ Docker CLI quen thuộc mà không cần chạy trình nền để phục vụ và hành động theo yêu cầu API. Thay vì mô hình máy khách/máy chủ, Podman thực hiện mô hình fork/exec cục bộ, và Red Hat thấy nó giúp đơn giản hóa rất nhiều việc kiểm soát và bảo mật vòng đời của container.
Podman mô phỏng các lệnh client khác nhau mà Docker cung cấp, và một số người ủng hộ, thậm chí khuyến khích người dùng mới chuyển từ lệnh docker sang podman, để dễ dàng di chuyển hơn. Trong số các bộ lệnh mô phỏng Docker mà Podman cung cấp, là lệnh podman build. Nó được sử dụng để xây dựng image container tuân thủ OCI , sử dụng Dockerfile làm nguồn cho các bước xây dựng khác nhau. Theo nghĩa đó, nó gần như giống hệt với lệnh docker build command, nhưng không có phần trên của daemon Docker.
Tất cả các đối số lệnh docker build quen thuộc đều có sẵn trong podman build (lưu lại cho một đối số lẻ vẫn chưa được thực hiện, như --cache-from), với một số đối số bổ sung được yêu cầu thay cho một số tính năng thường được cung cấp bởi daemon Docker (ví dụ: giao tiếp registry). Chuyển đổi từ docker build sang podman build, sau đó, là một trải nghiệm liền mạch, ngoại trừ việc cần chỉ định nơi tìm image được tham chiếu mà không có tên image đủ điều kiện.
Quan tâm đến việc Giant Swarm song hành với OpenShift như thế nào? Đọc bài viết chia nhỏ những lợi ích chính của việc sử dụng Giant Swarm so với OpenShift .

Rootless Builds

Ngoài việc cung cấp trải nghiệm daemonless build, Podman cũng cung cấp một tính năng được tìm kiếm khác - rootless container builds. Trong lịch sử, vì Docker daemon, việc xây dựng image container bằng lệnh docker build cần nhiều đặc quyền root, một mức truy cập được quan tâm trong các tổ chức có ý thức bảo mật. Khi cung cấp khả năng thực hiện các bản dựng rootless, Podman giải quyết mối quan tâm này, nhưng không phải nó không có giới hạn.
Quá trình xây dựng image từ Dockerfiles liên quan đến việc tạo container tạm thời để chạy các lệnh để cài đặt các gói, truy xuất nội dung từ xa, xây dựng các tạo phẩm, v.v. Tạo và chạy container thông thường đòi hỏi quyền root. Vì vậy, làm thế nào để Podman thỏa mãn yêu cầu này? Để tránh sự cần thiết phải chạy các bản dựng với tư cách là người dùng root, Podman sử dụng user namespaces. Namespaces cung cấp một cơ chế cô lập cho các quy trình Linux và là thành phần chính của sự trừu tượng hóa container. Nếu tập hợp namespaces của một container được tạo ra bao gồm user namespace, thì tác nhân khởi tạo container đó có thể là người dùng không có đặc quyền - nói cách khác, với user namespaces, Podman có thể sử dụng các container để tạo ra các image rootless.
User namespaces cung cấp cách map một phạm vi ID người dùng và nhóm không có đặc quyền (UID/GID) từ user namespace mặc định của máy chủ, đến một bộ UID/GID khác trong user namespace mới được liên kết với một container. Theo cách này, UID/GID không có đặc quyền trên máy chủ có thể được map an toàn đến người dùng gốc (UID / GID = 0) bên trong một container, cho phép container thi hành các đặc quyền nâng cao mà nó có thể cần như một phần của quá trình xây dựng image ( ví dụ, cài đặt các gói hệ điều hành). Nhưng nhờ vào map, container chỉ có quyền truy cập tệp tương tự trên máy chủ được tạo cho người dùng không có đặc quyền đã thực hiện lệnh podman build. Điều này có nghĩa là hệ thống tập tin của máy chủ được bảo vệ khỏi truy cập vô tình hoặc độc hại của container.

Hạn chế rootless hiện tại
Image mới thường được xây dựng từ image cơ sở ( hướng dẫn FROM trong Dockerfile), nội dung thông thường sẽ được sở hữu bởi người dùng với UID/GID = 0. Khi container được khởi động như một phần của container được tạo bởi người dùng không có đặc quyền, các tệp của container được sở hữu bởi UID/GID = 0 trên máy chủ, trong khi quy trình của container sẽ chỉ có quyền truy cập tệp được liên kết với người dùng không có quyền. Điều này có nghĩa là quá trình của container không thể ghi vào hệ thống tập tin của nó, gây cản trở nghiêm trọng việc xây dựng image container. Để các tệp từ image có quyền sở hữu chính xác bên trong một container, bộ UID/GID cần phải được 'dịch chuyển' nội tuyến với user namespaces mapping. Hiện tại, không có phương tiện tối ưu để đạt được điều này.
Khi rootless podman build được khởi tạo và một container yêu cầu quyền sở hữu 'shift', nội dung hệ thống tập tin được sao chép và quyền sở hữu được thay đổi (chown) để phản ánh mapping. Điều này rõ ràng là không hiệu quả về mặt không gian, và mất thời gian, có thể ảnh hưởng nghiêm trọng đến thời gian xây dựng container. Một trong những ý tưởng được đưa ra là nhiều container và image có thể chia sẻ nội dung của image mà không bị trùng lặp. Lý tưởng nhất là sự thay đổi này sẽ xảy ra mà không bị trùng lặp như là một phần của hoạt động gắn kết khi hệ thống tập tin của container được lắp ráp từ các lớp cấu thành của nó.
Hầu hết các thời gian chạy của container đều sử dụng overlayfs để lắp ráp hệ thống tệp của container, và nó không hỗ trợ chuyển UID/GID trên mounts, nhưng gần đây Ubuntu đã trở thành bản phân phối Linux đầu tiên hỗ trợ cơ chế in-kernel (shiftfs) cho overlays. Nó đã được đưa vào sử dụng trong dự án LXD của Linux Container .
Đối với Podman, một biện pháp khắc phục tạm thời là giới thiệu tùy chọn mount cho overlayfs trong Linux kernel phiên bản 4.19. Nó chỉ sao chép metadata cho các tệp và thư mục vào lớp đọc/ghi, thay vì chỉnh sửa nội dung chính. Tuy nhiên, cuối cùng, cộng đồng đang chờ đợi sự hỗ trợ trong mainline Linux kernel để chuyển UID/GID giúp đạt được mục tiêu này.
Hãy chuyển sang Buildah và giải thích nó liên quan đến nó như thế nào, và khác với podman build ra sao.

Buildah
Chưa đề cập đến việc podman build sử dụng Buildah để thực hiện các bản dựng image container. Điều này có nghĩa là các bản dựng daemonless và rootless cũng là một tính năng của Buildah. Không giống như Podman, Buildah có chức năng xây dựng image cụ thể cho container và có một số tính năng vượt ra ngoài việc xây dựng image dựa trên Dockerfiles.
Phần lớn các image container trên thị trường đã được xây dựng với Dockerfile là tài liệu tham khảo bất biến cho image. Việc podman build sử dụng Dockerfiles để xây dựng image và Buildah cũng có thể xây dựng image từ Dockerfiles bằng cách sử dụng lệnh buildah bud đang được thảo luận. Nhưng một lần nữa, Buildah được truyền cảm hứng từ việc tìm kiếm một phương pháp thay thế cho Dockerfile phổ biến để xây dựng image container. Lý do căn bản là chỉ cần một "bundle" đại diện cho image tuân thủ OCI và cách đạt được mục tiêu cuối cùng mà không cần Dockerfile. Những người bảo trì của Buildah khẳng định rằng Dockerfile là một hạn chế cần cải thiện.

Cách thức hoạt động của Buildah
Bất chấp mong muốn độc lập từ Dockerfile, Buildah sử dụng một quy trình tương tự để xây dựng image container. docker build chạy một container mới để xử lý từng lệnh Dockerfile, dẫn đến việc tạo ra nội dung mới hoặc thay đổi hoặc image metadata trước khi container được liên kết với một image mới. Hướng dẫn tiếp theo được xử lý trong một container mới dựa trên image được tạo trước đó, và sau đó được liên kết với một image mới, v.v. Buildah cũng làm điều tương tự, nhưng thay vì sử dụng các lệnh Dockerfile, nó triển khai các lệnh phụ Buildah và không yêu cầu 'liên kết' sau khi thực hiện mỗi lệnh phụ.
Quá trình xây dựng có thể bắt đầu với lệnh buildah from và một container đang chạy dựa trên image được chỉ định làm đối số. Nó tương tự như lệnh FROM Dockerfile. Để thực thi các lệnh trong container như là một phần của việc xây dựng image (ví dụ: để tạo người dùng mới hoặc xây dựng một tạo phẩm từ nguồn của nó), tác giả image có thể sử dụng buildah run , có thể tương tác khi được yêu cầu. Ngoài việc chạy các lệnh tạo nội dung cho image container, Buildah cũng cung cấp phương tiện để xác định metadata cho image, sử dụng buildah config. Nó cho phép đặc tả cổng tiếp xúc, người dùng mặc định, container entrypoint, v.v. Các lệnh buildah copy buildah add tương tự như lệnh COPY ADD Dockerfile để lấy nội dung bên ngoài vào image. Với việc sử dụng buildah mount, nó thậm chí có thể gắn hệ thống tập tin gốc của container tại một vị trí phù hợp trên máy chủ để thao tác tiếp theo với các công cụ có nguồn gốc từ chính máy chủ.
Khi một tác giả image tự tin rằng họ đã hoàn thành việc tạo image của mình, lệnh buildah commit liên kết container với image mới.

Quy trình làm việc
Có một số điểm tương đồng rõ ràng giữa sự kết hợp giữa Dockerfile với docker build và Buildah. Nhưng Dockerfile áp đặt việc thực hiện tuần tự các hướng dẫn phụ thuộc, vậy Buildah cung cấp thứ tự và độ lặp lại tương tự như thế nào trong một bản dựng container? Từ phía daemon build engine áp đặt lệnh này cho một docker build, nó gợi ý rằng container được xây dựng sử dụng Buildah cần được xác định theo chương trình, ví dụ như sử dụng Bash.
Mã:
#!/bin/bash

id=$(buildah from --pull node:10)
buildah run $id mkdir -p /usr/src/app
buildah config --workingdir /usr/src/app $id
buildah copy $id $PWD .
buildah run --net host $id npm install
buildah config --port 1337 --entrypoint '["npm", "start"]' $id
buildah commit $id example-app
Ví dụ đơn giản ở trên cho thấy cách đạt được một bản dựng lặp lại bằng Buildah trong tập lệnh Bash.
Khi thực hiện phương pháp xây dựng image, Buildah sẽ loại bỏ mọi phụ thuộc vào quy trình daemon chạy dài và hơn nữa, giải phóng trình xây dựng image khỏi các ràng buộc của cú pháp Dockerfile. Các image được tạo bởi Buildah có thể được đẩy vào container registry, sau đó được kéo bởi Podman hoặc daemon Docker và sẽ hoạt động trơn tru trong thời gian chạy của container hỗ trợ thông số OCI.

Xây dựng bộ nhớ đệm và thực thi song song
Nếu image được xây dựng bằng Dockerfile và buildah bud , thì các lớp image được lưu trữ để sử dụng lại trong các bản dựng tiếp theo. Việc chuyển đổi sang Buildah sau khi áp dụng Docker có thể dự đoán được vì nó giúp tăng đáng kể tốc độ thực hiện xây dựng. Nhưng, đừng mong đợi bộ nhớ đệm khả dụng khi xây dựng image bằng cách sử dụng các lệnh Buildah trong một tập lệnh. Bộ nhớ đệm không khả dụng, điều đó có nghĩa là toàn bộ các bước xây dựng cần được thực hiện trên mỗi lần lặp xây dựng mới, bất kể có thay đổi nội dung hoặc lệnh xảy ra hay không.
Ngoài ra, Buildah thực hiện các bước xây dựng của mình một cách tuần tự, ngay cả khi một bước xây dựng hoàn toàn độc lập với bước khác. Tính năng xây dựng song song đang được xem xét, hiện tại nó không có sẵn trong Buildah, điều này có thể kéo dài thêm thời gian cần thiết để thực hiện các bản dựng image container phức tạp.

Phần kết luận
podman build nên được sử dụng khi tạo image với Dockerfiles, và Buildah nên được sử dụng nếu cú pháp Dockerfile quá hạn chế, hoặc nếu muốn sử dụng một cách tiếp cận script-like để lặp lại. Điều đáng nói là image container và Dockerfiles gần như đồng nghĩa với nhau, vì vậy vẫn còn phải xem liệu Buildah có được đủ sự chú ý để vượt ra ngoài cộng đồng Red Hat để vượt qua Dockerfile hay không.
Podman và Buildah cung cấp hai tính năng được tìm kiếm nhiều nhất để xây dựng image container; xây dựng daemonless và rootless. Tuy nhiên, chúng cũng cạnh tranh với nhau và vẫn thiếu một số tính năng mà các công cụ tương tự hiện đang cung cấp.

Nguồn: https://blog.giantswarm.io/
 
Top