Berbagi teknologi

Gunakan docker buildx untuk membuat image lintas platform

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

buildx adalah alat pembangunan yang secara resmi disediakan oleh Docker. Ini dapat membantu pengguna membangun image Docker dengan cepat dan efisien, dan mendukung pembangunan berbagai platform. Dengan menggunakan buildx, pengguna dapat membuat image untuk beberapa arsitektur, seperti arsitektur x86 dan arm, dalam satu perintah tanpa harus mengoperasikan beberapa perintah build secara manual. Selain itu, buildx juga mendukung konstruksi multi-tahap dan caching Dockerfile, yang dapat sangat meningkatkan efisiensi dan kecepatan konstruksi gambar.

buildx adalah plug-in CLI yang mengelola build Docker. Lapisan yang mendasarinya menggunakan BuildKit untuk memperluas kemampuan build Docker.

BuildKit adalah mesin build berkinerja tinggi yang secara resmi disediakan oleh Docker, yang dapat digunakan untuk menggantikan mesin build asli Docker. Dibandingkan dengan mesin aslinya, BuildKit memiliki kecepatan build yang lebih cepat, paralelisme yang lebih tinggi, penggunaan sumber daya yang lebih sedikit, dan keamanan yang lebih baik.

Untuk menginstal dan menggunakan buildx, nomor versi Docker Engine lebih besar atau sama dengan 19.03.

Strategi membangun citra lintas platform

Pembuatnya mendukung berbagai strategi untuk membangun gambar lintas platform.

Menggunakan dukungan emulasi QEMU di kernel

Jika Anda menggunakan Docker Desktop, QEMU sudah didukung dan merupakan strategi paling sederhana untuk membangun image lintas platform. Itu tidak memerlukan perubahan apa pun pada Dockerfile asli. BuildKit akan mengimplementasikan eksekusi program lintas platform melalui fungsi kernel Linux binfmt_misc.

prinsip bekerja:

QEMU adalah simulator prosesor yang dapat mensimulasikan arsitektur CPU yang berbeda. Kita dapat memahaminya sebagai bentuk lain dari mesin virtual. Di buildx, QEMU digunakan untuk mengeksekusi biner untuk arsitektur non-native selama proses build. Misalnya, saat membuat image ARM pada host x86, QEMU dapat mensimulasikan lingkungan ARM dan menjalankan binari ARM.

binfmt_misc adalah modul kernel Linux yang memungkinkan pengguna mendaftarkan format file yang dapat dieksekusi dan penerjemah yang sesuai.Ketika kernel menemukan file yang dapat dieksekusi dengan format yang tidak diketahui, binfmt_misc digunakan untuk menemukan penerjemah yang terkait dengan format file (dalam hal ini QEMU) dan menjalankan file tersebut . Fungsi ini dimatikan pada platform rk3568.

Kombinasi QEMU dan binfmt_misc memungkinkan pembangunan lintas platform melalui buildx. Hal ini memungkinkan kami membuat image Docker untuk satu arsitektur pada host untuk arsitektur lain tanpa harus memiliki perangkat keras target sebenarnya.

Meskipun Docker Desktop telah dikonfigurasi sebelumnya dengan dukungan binfmt_misc untuk platform lain, untuk versi Docker lainnya, Anda mungkin perlu menggunakan image tonistiigi/binfmt untuk memulai kontainer istimewa untuk mendapatkan dukungan.

docker run --privileged --rm tonistiigi/binfmt --install all

Menjalankan perintah ini akan menginstal program penerjemah dengan arsitektur berbeda, yaitu simulator qemu di direktori /usr/bin:

Modul binfmt_misc dimuat di server kompilasi kami:

Peran docker buildx menggunakan qemu

Docker Buildx adalah fitur eksperimental Docker yang memperluas kemampuan build Docker, termasuk penggunaan multi-node, qemu, dll. QEMU adalah perangkat lunak mesin virtual sumber terbuka yang dapat mensimulasikan berbagai CPU dan perangkat keras lainnya, memungkinkan kita membangun image sistem operasi lain pada satu sistem operasi.

Menggunakan fungsi qemu di Docker Buildx dapat membantu kita membuat image Docker untuk berbagai arsitektur berbeda (seperti ARM, MIPS, dll.).

Berikut ini adalah contoh sederhana yang menunjukkan cara menggunakan Docker Buildx dan QEMU untuk membangun image Docker untuk arsitektur ARM:

  1. # 创建一个新的 buildkit 实例
  2. docker buildx create --name mybuilder --use
  3. # 启动 buildkit 实例
  4. docker buildx start mybuilder
  5. # 启用 QEMU 驱动支持
  6. docker buildx inspect --bootstrap
  7. # 构建一个面向 ARM 架构的 Docker 镜像
  8. docker buildx build --platform linux/arm/v7 -t myimage:latest .

Dalam contoh ini,--platform Parameternya menentukan bahwa platform target yang ingin kita bangun adalah ARM v7. Dengan cara ini, Docker akan menggunakan QEMU untuk mensimulasikan lingkungan ARM dan membangun image Docker untuk arsitektur ARM pada mesin arsitektur x86.

sistem file binfmt_misc

binfmt-misc adalah fungsi yang disediakan oleh kernel Linux mirip dengan asosiasi file di Windows, tetapi lebih kuat dari asosiasi file adalah ia tidak hanya dapat menilai berdasarkan nama akhiran file, tetapi juga dapat dibuka menggunakan program berbeda berdasarkan file tersebut konten (Byte Ajaib) . Skenario penggunaan umumnya adalah menggunakan qemu untuk menjalankan file biner pada platform arsitektur lain.

Aktifkan binfmt-lain-lain

Untuk mengaktifkannya sementara, gunakan perintah berikut:

$ sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc

Metode ini akan menjadi tidak valid setelah dimulai ulang. Jika Anda ingin menerapkannya dalam waktu lama, Anda dapat menambahkan baris ke file /etc/fstab:

none  /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0

Anda dapat menggunakan perintah berikut untuk memeriksa apakah pembukaan berhasil:

  1. $ mount | grep binfmt_misc
  2. binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
  3. $ ls -l /proc/sys/fs/binfmt_misc
  4. 总用量 0
  5. --w------- 1 root root 0 25 22:55 register
  6. -rw-r--r-- 1 root root 0 25 22:55 status

Pertama siapkan program dengan arsitektur arm64. Setelah menjalankannya, kesalahan dilaporkan:

bash: ./go-test:无法执行二进制文件: 可执行文件格式错误

Sekarang, mari kita jalankan perintah apt install qemu-user-binfmt, lalu jalankan program arm64 di atas dan ternyata dapat berjalan normal. Setelah menginstal qemu-user-binfmt, beberapa file akan dibuat di direktori /proc/sys/fs/binfmt_misc, termasuk satu qemu-aarch64.

  1. root@ubuntu:/proc/sys/fs/binfmt_misc# cat qemu-aarch64
  2. enabled
  3. interpreter /usr/bin/qemu-aarch64-static
  4. flags: OC
  5. offset 0
  6. magic 7f454c460201010000000000000000000200b700
  7. mask ffffffffffffff00fffffffffffffffffeffffff
  8. root@ubuntu:/proc/sys/fs/binfmt_misc#

File ini menjelaskan file aturan:

Baris pertama yang diaktifkan menunjukkan bahwa aturan tersebut diaktifkan;

Penerjemah baris kedua /usr/bin/qemu-aarch64-static menunjukkan penggunaan /usr/bin/qemu-aarch64-static untuk mengeksekusi file biner;

Baris ketiga: OC melambangkan bendera lari, arti spesifiknya adalah sebagai berikut:

P: singkatan dari melestarikan-argv, artinya saat memanggil simulator, parameter asli (argv) akan dipertahankan.Hal ini berguna untuk situasi di mana program senyap perlu mengetahui namanya sendiri (yaitu argv[0]) saat runtime

O: mewakili offset, artinya sebelum memulai simulator, offset perlu dibaca dari file biner, dan offset ini akan digunakan sebagai parameter simulator.

C: adalah singkatan dari kredensial, artinya emulator akan berjalan dengan ID pengguna dan ID grup yang sama dengan yang digunakan oleh program aslinya, yang membantu memastikan bahwa emulator berjalan dengan izin yang sama dengan program aslinya.

Baris keempat: offset 0 berarti mulai membaca file dari nilai 0;

Baris kelima: magic 7f454c460201010000000000000000000200b700 mewakili modulo byte yang akan dicocokkan;

Bidang ajaib pada header file ELF arsitektur arm64 adalah sebagai berikut, artinya sistem file binfmt_misc dapat menentukan simulator arsitektur mana yang akan digunakan untuk menjalankan file berdasarkan bidang ajaib pada file ELF:

Di bawah ini adalah dua arsitektur yang berbeda

Arsitektur Mips: 7f454c4601020100000000000000000000020008
arsitektur arm64: 7f454c460201010000000000000000000200b700

Baris 6: mask ffffffffffffff00ffffffffffffffffffffffff mewakili byte mask, yang dapat digunakan untuk mengabaikan beberapa byte yang tidak penting dalam file.

Menjalankan image Docker arsitektur arm64 di sistem x86_64

Sekarang kami menggunakanburuh pelabuhanPerintah menjalankan gambar arm64:

  1. $ docker run -it arm64v8/ubuntu bash
  2. Unable to find image 'arm64v8/ubuntu:latest' locally
  3. latest: Pulling from arm64v8/ubuntu
  4. 005e2837585d: Pull complete
  5. Digest: sha256:ba545858745d6307f0d1064d0d25365466f78d02f866cf4efb9e1326a4c196ca
  6. Status: Downloaded newer image for arm64v8/ubuntu:latest
  7. standard_init_linux.go:207: exec user process caused "no such file or directory"

Setelah beberapa eksplorasi, saya menemukan bahwa selama saya menjalankan perintah berikut:apt install qemu-user-static, lalu mulai buruh pelabuhanwadahItu normal.

Menggunakan cross-build multi-tahap di Dockerfile

Kompleksitas kompilasi silang tidak terletak pada Docker, tetapi pada program itu sendiri. Misalnya, program Go dapat dengan mudah dikompilasi silang. Anda hanya perlu menjalankan dua variabel lingkungan GOOS dan GOARCH saat membuat program menggunakan go build.

Buat pembangun

Untuk menggunakan buildx untuk membangun image lintas platform, pertama-tama kita perlu membuat pembuat, yang dapat diterjemahkan sebagai pembuat.

Gunakan perintah docker buildx ls untuk melihat daftar pembuat:

  1. root@ubuntu:/proc# docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS
  3. mybuild * docker-container
  4. mybuild0 unix:///var/run/docker.sock running linux/arm64*, linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386
  5. vigilant_hugle docker-container
  6. vigilant_hugle0 unix:///var/run/docker.sock stopped
  7. default docker
  8. default default running linux/amd64, linux/386

Tanda * menunjukkan pembuat yang sedang digunakan. Saat kami menjalankan perintah docker build, kami menggunakan pembuat ini untuk membuat image. DRIVER/ENDPOINT pada kolom kedua menunjukkan driver yang digunakan. buildx mendukung driver berikut:

  • buruh pelabuhan: Gunakan pustaka BuildKit yang digabungkan ke dalam daemon Docker, yang merupakan BuildKit default setelah menginstal Docker.
  • docker-container: Gunakan Docker untuk membuat container BuildKit khusus yang baru.
  • kubernetes: Membuat Pod BuildKit di cluster kubernetes.
  • jarak jauh: Hubungkan langsung ke daemon BuildKit yang dikelola secara manual.

Karena pembuat default yang menggunakan driver docker tidak mendukung pembuatan image lintas platform menggunakan satu perintah (parameter --platform dari pembuat default hanya menerima satu nilai), kita perlu membuat pembuat baru menggunakan driver docker-container .

Sintaks perintahnya adalah sebagai berikut:

$ docker buildx create --name=<builder-name> --driver=<driver> --driver-opt=<driver-options>

Arti dari parameter adalah sebagai berikut;

--name: Nama yang dibuat, wajib diisi.

--driver: Driver pembuat, defaultnya adalah wadah buruh pelabuhan.

--driver-opt: opsi driver. Misalnya, opsi --driver-opt=image=moby/buildkit:v0.11.3 dapat menginstal versi BuildKit yang ditentukan.

Kita dapat membuat pembangun baru menggunakan perintah berikut:

  1. $ docker buildx create --name mybuilder
  2. mybuilder

Periksa kembali daftar pembuatnya:

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock inactive
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Anda dapat menemukan bahwa build yang dipilih telah dialihkan ke Mybuilder. Jika tidak dipilih, Anda perlu menggunakan perintah docker buildx use mybuilder secara manual untuk mengganti build.

Mulai pembangun

Mybuilder kami yang baru dibuat saat ini tidak aktif dan perlu dijalankan sebelum dapat digunakan.

  1. $ docker buildx inspect --bootstrap mybuilder
  2. [+] Building 16.8s (1/1) FINISHED
  3. => [internal] booting buildkit 16.8s
  4. => => pulling image moby/buildkit:buildx-stable-1 16.1s
  5. => => creating container buildx_buildkit_mybuilder0 0.7s
  6. Name: mybuilder
  7. Driver: docker-container
  8. Nodes:
  9. Name: mybuilder0
  10. Endpoint: unix:///var/run/docker.sock
  11. Status: running
  12. Buildkit: v0.9.3
  13. Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

Subperintah inspeksi digunakan untuk memeriksa status build. Gunakan parameter --bootstrap untuk memulai pembuat mybuilder. Periksa kembali daftar pembuat.

  1. $ docker buildx ls
  2. NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
  3. mybuilder * docker-container
  4. mybuilder0 unix:///var/run/docker.sock running v0.9.3 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
  5. default docker
  6. default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
  7. desktop-linux docker
  8. desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6

Nilai yang ditampilkan di kolom PLATFORMS

linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 didukung oleh pembuat saat ini Semua platform.

Sekarang gunakan perintah docker ps untuk melihat bahwa wadah BuildKit yang sesuai dengan pembuat mybuilder telah dimulai.

  1. $ docker ps
  2. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  3. b8887f253d41 moby/buildkit:buildx-stable-1 "buildkitd" 4 minutes ago Up 4 minutes buildx_buildkit_mybuilder0

Kontainer ini digunakan untuk membantu kami dalam membangun image lintas platform.

Gunakan pembuat untuk membuat gambar lintas platform

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .

Sintaks docker buildx build sama dengan docker build. Parameter --platform menunjukkan platform target untuk membangun gambar, -t menunjukkan Tag gambar, . menunjukkan bahwa konteksnya adalah direktori saat ini。 

Satu-satunya hal yang tidak berfungsi adalah dukungan untuk parameter --platform. Parameter --platform dari docker build hanya mendukung penyampaian satu informasi platform, seperti --platform linux/arm64, yang berarti bahwa satu gambar platform dapat dibangun pada suatu waktu.

Menggunakan docker buildx build untuk membuat image mendukung transmisi beberapa informasi platform secara bersamaan, dipisahkan dengan koma bahasa Inggris, sehingga mewujudkan fungsi membuat beberapa image lintas platform hanya dengan satu perintah.

Setelah menjalankan perintah di atas, kita akan mendapat peringatan:

WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

Peringatan ini mengingatkan kita bahwa kita belum menentukan output untuk driver docker-container. Hasil yang dihasilkan hanya akan disimpan dalam cache build. Gunakan --push untuk memasukkan image ke repositori jarak jauh Docker Hub, dan gunakan --load untuk menyimpan gambar secara lokal.

Ini karena mybuilder yang baru kami buat memulai sebuah container untuk menjalankan BuildKit. Ia tidak dapat secara langsung mengeluarkan gambar lintas platform yang dibangun ke mesin lokal atau mendorongnya ke jarak jauh.

Kita dapat mencoba menentukan --load untuk menyimpan gambar di host lokal.

  1. $ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load
  2. [+] Building 0.0s (0/0)
  3. ERROR: docker exporter does not currently support exporting manifest lists

Hasilnya akan menjadi log kesalahan. Tampaknya ini tidak mendukung ekspor gambar lintas platform ke lokal. Ini sebenarnya karena beberapa --platforms diteruskan. Jika --platform hanya melewati satu platform, Anda dapat menggunakan --load untuk menampilkan gambar yang dibuat ke dalamnya mesin.

Kemudian kita hanya dapat mendorong gambar lintas platform ke gudang jarak jauh melalui parameter --push. Namun, sebelum melakukan ini, Anda perlu memastikan untuk menggunakan login buruh pelabuhan untuk menyelesaikan login.

$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push

Sekarang masuk ke Docker Hub dan Anda dapat melihat gambar lintas platform yang didorong.

Kita juga dapat menggunakan imagestools untuk memeriksa informasi manifes dari gambar lintas platform. Perintah ini hanya dapat digunakan untuk mendapatkan informasi gambar di gudang, dan gambar lokal tidak dapat dilihat.

  1. $ docker buildx imagetools inspect jianghushinian/hello-go
  2. Name: docker.io/jianghushinian/hello-go:latest
  3. MediaType: application/vnd.docker.distribution.manifest.list.v2+json
  4. Digest: sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104db
  5. Manifests:
  6. Name: docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6
  7. MediaType: application/vnd.docker.distribution.manifest.v2+json
  8. Platform: linux/arm64
  9. Name: docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441ba
  10. MediaType: application/vnd.docker.distribution.manifest.v2+json
  11. Platform: linux/amd64

 

Seperti yang Anda lihat, gambar lintas platform ini berisi gambar dari dua platform target, yaitu linux/arm64 dan linux/amd64.