Bagaimana cara membuat gambar buruh pelabuhan terkecil bekerja setiap saat?

19

Tujuan: untuk membuat gambar buruh pelabuhan yang bekerja terkecil setiap saat

Arus

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

Mencoba

Menambahkan langkah pembersihan di akhir Dockerfile:

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

mengurangi ukuran gambar sedikit:

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

Diskusi

Saya telah membangun berbagai gambar buruh pelabuhan. Setiap kali saya mencoba mengurangi ukuran gambar yang dibuat, tetapi saya selalu merasa itu terlalu besar. Saya mencari skrip yang telah dibuat oleh seseorang di github yang menghapus semua paket yang tidak berguna dari gambar sehingga ukuran gambar yang dibuat akan sekecil mungkin.

Seperti yang saya katakan, saya selalu berusaha mengurangi ukuran gambar, tetapi saya ingin menerapkan ini secara konsisten sehingga setiap gambar yang saya buat mulai sekarang akan sekecil mungkin.

Pertanyaan

Bagaimana cara membuat gambar buruh pelabuhan terkecil bekerja setiap saat?

030
sumber

Jawaban:

1

Ada berbagai teknik yang terlibat, tanpa solusi tunggal. Anda mungkin ingin melakukan beberapa hal berikut:


Pertama, optimalkan layer gambar Anda untuk digunakan kembali. Masukkan langkah-langkah yang sering diubah kemudian di Dockerfile untuk meningkatkan kemungkinan bahwa lapisan awal di-cache dari build sebelumnya. Lapisan yang digunakan kembali akan muncul sebagai lebih banyak ruang disk dalam docker image ls, tetapi jika Anda memeriksa sistem file yang mendasarinya, hanya satu salinan dari setiap lapisan yang pernah disimpan pada disk. Itu berarti 3 gambar masing-masing 2 GB, tetapi yang hanya memiliki 50 MB berbeda dalam beberapa lapisan terakhir pembangunan, hanya akan memakan ruang disk 2,1 GB, meskipun daftar membuatnya tampak bahwa mereka menggunakan 6 GB karena Anda menghitung ganda masing-masing lapisan yang digunakan kembali.

Penggunaan kembali lapisan adalah mengapa Anda melihat gambar dengan dependensi build yang jarang berubah, instal terlebih dahulu sebelum menyalin kode. Lihat contoh python yang memiliki pola seperti:

FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]

Pilih gambar dasar minimal. Inilah sebabnya mengapa Anda melihat orang-orang pergi dari ubuntuke debian:slim(varian slim lebih kecil, pengiriman dengan alat yang lebih sedikit), atau bahkan alpine. Ini mengurangi ukuran titik awal Anda, dan sangat membantu jika Anda terus-menerus menarik versi baru gambar dasar. Namun, jika gambar dasar Anda jarang berubah, penggunaan kembali lapisan menghilangkan banyak keuntungan dari gambar dasar minimal.

Gambar dasar terkecil yang dapat Anda pilih adalah scratch, yang bukan apa-apa, tidak ada shell atau pustaka, dan hanya berguna untuk binari yang dikompilasi secara statis. Jika tidak, pilih gambar dasar yang mencakup alat yang Anda butuhkan tanpa banyak alat yang tidak Anda butuhkan.


Selanjutnya, setiap langkah yang mengubah atau menghapus file harus dikombinasikan dengan langkah-langkah sebelumnya yang membuat file itu. Kalau tidak, sistem file berlapis, yang menggunakan copy-on-write bahkan pada hal-hal seperti perubahan izin file, akan memiliki file asli di lapisan sebelumnya dan ukuran gambar tidak akan menyusut ketika Anda menghapus file. Inilah sebabnya mengapa rmperintah Anda tidak berpengaruh pada ruang disk yang dihasilkan. Sebagai gantinya, Anda dapat membuat rantai perintah, seperti:

RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
 && ... \
 && apt-get purge -y wget \
 && rm -r a-build-dir \
 && apt-get purge -y a-package

Perhatikan bahwa penggunaan perintah yang berlebihan dapat memperlambat build Anda karena Anda perlu menginstal ulang toolset yang sama setiap kali prasyarat berubah (misalnya kode ditarik dengan wget). Lihat multi-tahap di bawah ini untuk alternatif yang lebih baik.


File apa pun yang Anda buat yang tidak Anda butuhkan dalam gambar yang dihasilkan harus dihapus, pada langkah yang membuatnya. Ini termasuk cache paket, log, halaman manual, dll. Untuk menemukan file apa yang sedang dibuat di setiap layer, Anda dapat menggunakan alat seperti wagoodman / dive (yang saya belum diperiksa secara pribadi dan akan menyatakan kehati-hatian karena dijalankan dengan akses root penuh) pada host Anda), atau Anda dapat membuat gambar buruh pelabuhan tanpa memangkas wadah perantara dan kemudian melihat diff dengan:

# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name . 
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a 
# examine any of those containers
docker container diff ${container_id} 
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune

Dengan masing-masing kontainer menengah, diff akan menunjukkan file apa yang ditambahkan, diubah, atau dihapus pada langkah yang (ini ditunjukkan dengan A, Catau Dsebelum setiap nama file). Perbedaan yang diperlihatkan adalah sistem file baca / tulis khusus kontainer, yang merupakan file apa pun yang diubah oleh wadah dari status gambar menggunakan copy-on-write.


Cara terbaik untuk mengurangi ukuran gambar adalah menghilangkan komponen yang tidak dibutuhkan, seperti kompiler, dari gambar yang Anda kirim. Untuk itu, multi-stage build memungkinkan Anda mengkompilasi dalam satu tahap, dan kemudian hanya menyalin artefak yang dihasilkan dari tahap build ke gambar runtime yang hanya memiliki minimum yang diperlukan untuk menjalankan aplikasi. Ini menghindari perlunya mengoptimalkan langkah-langkah pembangunan karena tidak dikirimkan dengan gambar yang dihasilkan.

FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
RUN ... # perform any download/compile steps

FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]

Multi-stage sangat ideal dengan binari yang dikompilasi secara statis yang dapat Anda jalankan dengan awal sebagai gambar dasar Anda, atau beralih dari lingkungan kompilasi seperti JDK ke runtime seperti JRE. Ini adalah cara termudah untuk secara dramatis mengurangi ukuran gambar Anda sambil tetap membuat cepat. Anda masih dapat melakukan chaining langkah-langkah di tahap rilis Anda jika Anda memiliki langkah-langkah yang mengubah atau menghapus file yang dibuat di langkah-langkah sebelumnya, tetapi untuk sebagian besar, COPYtahap dari mengisolasi tahap rilis dari semua lapisan mengasapi berpengalaman dalam tahap membangun sebelumnya.


Catatan, saya tidak merekomendasikan memencet gambar karena ini mengurangi ukuran satu gambar dengan mengorbankan menghilangkan penggunaan kembali lapisan. Itu berarti membangun di masa depan dari gambar yang sama akan memerlukan lebih banyak disk dan lalu lintas jaringan untuk mengirim pembaruan. Untuk kembali ke contoh pertama, squashing dapat mengurangi gambar Anda dari 2 GB menjadi 1 GB, tetapi tidak 3 gambar mungkin memakan 3 GB daripada 2.1 GB.

BMitch
sumber
25

A Dockerfilemembuat layer baru untuk setiap perintah dalam file. Karena layer baik, berlapis-lapis di atas satu sama lain - Anda tidak dapat menghapus file yang ditambahkan lapisan sebelumnya. Inilah sebabnya ketika Anda menginstal paket, atau mengunduh file, atau membuat build masing-masing dalam perintah yang terpisah - ini masih ada di dalam gambar, bahkan jika di lapisan berikutnya Anda menghapusnya.

Jadi, jika Anda hanya mengubah ini:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

Untuk ini:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

Anda akan mendapatkan gambar yang jauh lebih kecil.


Pilihan lain, adalah memencet gambar setelah Anda membuatnya. T: Bagaimana cara docker --squashkerja yang baru ?


Namun pilihan lain, adalah memilih gambar dasar yang ramping. Misalnya, gambar yang menggunakan Alpine Linux sebagai basis mereka alih-alih Debian, ambil hanya 10-15mb bukan 180-250mb. Dan ini sebelum menambahkan aplikasi dan data Anda sendiri. Banyak gambar dasar resmi di Docker Hub memiliki versi alpine.

Evgeny
sumber
3
2.37vs.1.47 GB
030
4

Mungkin bukan jawaban yang tepat, tetapi layak untuk diberikan alternatifnya.

Habitat Chef telah dibuat dengan pemikiran ini, menciptakan paket dengan semua dependensi yang dibutuhkan tanpa distro / basis gambar asing yang tidak Anda inginkan.

Ekstrak tentang apa yang penting di sini, ukuran wadah dari posting blog ini dengan aplikasi simpuljs sederhana:

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-exampleadalah gambar buruh pelabuhan dari buruh pelabuhan klasik sedangkan mfdii/mytutorialappgambar buruh pelabuhan diproduksi dengan habitat.

Jika ukuran adalah perhatian utama Anda dan Anda siap mengambil kurva pembelajaran dari rencana Habitat, ini bisa menjadi solusi untuk Anda.

Tensibai
sumber
0

Satu juga bisa menggunakan menyelam

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

untuk mendapatkan laporan tentang limbah apa yang bisa dihilangkan dari gambar buruh pelabuhan untuk mengurangi ukuran.

030
sumber
0

Jika Anda ingin memiliki lapisan pengembangan yang dapat digunakan kembali tetapi mengurangi penggunaan disk Anda untuk pengiriman, Anda dapat menghasilkan "lapisan pengiriman" yang digabungkan seperti ini:

  1. Pastikan Anda memiliki wadah yang menggunakan gambar Anda (jika Anda tidak memilikinya, mungkin gunakan sesuatu seperti docker run IMAGE echo, jika perintah gema tersedia)
  2. Temukan id wadah (mungkin menggunakan docker container ls -l)
  3. Pipa docker exportuntuk docker importmembuat lapisan gabungan (seperti docker export 20f192c6530a | docker import - project:merged)

Ini akan membuat layer pengembangan Anda tetap ada tetapi memberi Anda gambar yang lebih kecil dan digabungkan yang dapat Anda berikan.

Bill Burdick
sumber
0

Membangun multi tahap. Gunakan gambar yang memiliki semua komponen build Anda untuk membangun aplikasi Anda, dan gambar runtime yang lebih ringan. Salin saja artefak bangunan Anda ke gambar runtime. Tidak perlu menghapus apa pun.

https://docs.docker.com/develop/develop-images/multistage-build/

jujur
sumber
0

simple .. buruh pelabuhan ps memeriksa gambar yang sedang berjalan saat ini .. untuk contoh file sederhana di bawah ini ..

DARI ubuntu16

MAINTAINER sreeni (email / domain)

Jalankan pembaruan apt-get

RUN apt-get install -y nginx

ENTRYPOINT ["/ usr / sbin / nginx", "- g", "daemon off;"]

EXPOSE 80 (port)

file buruh pelabuhan sederhana ...

gunakan di bawah perintah buruh pelabuhan

docker run -d -p 80:80 --name server web ubuntu16 (nama gambar) setelah itu periksa localhost atau alamat ip: 80 (buka browser dan periksa)

sreeniwl
sumber
1
tolong perbaiki format jawaban Anda ...
Pierre.Vriens