GNU/Linux >> Belajar Linux >  >> Panels >> Docker

Mengoptimalkan ukuran Gambar ASP.NET Core Docker

Ada posting bagus dari Steve Laster pada tahun 2016 tentang mengoptimalkan ukuran ASP.NET Docker Image. Sejak itu Docker telah menambahkan file build multi-tahap sehingga Anda dapat melakukan lebih banyak dalam satu Dockerfile...yang terasa seperti satu langkah meskipun sebenarnya tidak. Container adalah tentang penerapan yang mudah dan andal, dan juga tentang kepadatan. Anda ingin menggunakan memori sesedikit mungkin, tentu saja, tetapi juga bagus untuk membuatnya sekecil mungkin sehingga Anda tidak menghabiskan waktu untuk memindahkannya di sekitar jaringan. Ukuran file gambar juga dapat mempengaruhi waktu startup untuk container. Ditambah lagi rapi.

Saya telah membangun 6 node Raspberry Pi (ARM) Kubenetes Cluster di meja saya - seperti yang Anda lakukan - minggu ini, dan saya perhatikan bahwa ukuran gambar saya sedikit lebih besar dari yang saya inginkan. Ini adalah masalah yang lebih besar karena ini adalah sistem dengan daya yang relatif rendah, tetapi sekali lagi, mengapa membawa sekitar x megabyte yang tidak perlu jika Anda tidak perlu?

Alex Ellis memiliki blog yang bagus tentang membangun aplikasi .NET Core untuk Raspberry Pi bersama dengan video YouTube. Dalam video dan blognya, dia membuat aplikasi konsol "Console.WriteLine()", yang sangat bagus untuk OpenFaas (platform tanpa server sumber terbuka) tetapi saya juga ingin memiliki aplikasi ASP.NET Core di klaster Raspberry Pi k8s saya. Dia memasukkan ini sebagai "tantangan" di blognya, jadi tantangan diterima! Terima kasih atas semua bantuan dan dukungan Anda, Alex!

ASP.NET Core di Docker (di ARM)

Pertama saya membuat aplikasi dasar ASP.NET Core. Saya bisa membuat Web API, tapi kali ini saya akan membuat MVC dengan Razor Pages. Untuk lebih jelasnya, mereka adalah hal yang sama hanya dengan titik awal yang berbeda. Saya selalu dapat menambahkan halaman atau menambahkan JSON, nanti.

Saya mulai dengan "dotnet new mvc" (atau dotnet pisau cukur baru, dll). Saya akan menjalankan ini di Docker, dikelola oleh Kuberenetes, dan sementara saya selalu dapat mengubah WebHost di Program.cs untuk mengubah cara server web Kestrel memulai seperti ini:

WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002")

Untuk kasus penggunaan Docker, lebih mudah untuk mengubah URL pendengar dengan Variabel Lingkungan. Tentu, bisa jadi 80, tapi saya suka 5000. Saya akan menyetel variabel lingkungan ASPNETCORE_URLS ke http://+:5000 saat saya membuat Dockerfile.

Dockerfile MultiStage yang Dioptimalkan untuk ASP.NET

Ada sejumlah cara yang "benar" untuk melakukan ini, jadi Anda sebaiknya memikirkan skenario Anda. Anda akan melihat di bawah bahwa saya menggunakan ARM (karena Raspberry Pi) jadi jika Anda melihat kesalahan menjalankan wadah Anda seperti "qemu:Unsupported syscall:345" lalu Anda mencoba menjalankan gambar ARM di x86/x64. Saya akan membuat wadah ARM dari Windows tetapi saya tidak dapat menjalankannya di sini. Saya harus mendorongnya ke registri wadah dan kemudian memberi tahu cluster Raspberry Pi saya untuk menariknya ke bawah dan MAKA itu akan berjalan, di sana.

Inilah yang saya miliki sejauh ini. CATATAN ada beberapa hal yang dikomentari, jadi berhati-hatilah. Ini adalah latihan pembelajaran bagi saya. Jangan kamu copy/paste kecuali kamu tahu ada apa! Dan jika ada kesalahan, inilah GitHub Gist dari Dockerfile saya untuk Anda ubah dan tingkatkan.

Penting untuk dipahami bahwa .NET Core memiliki SDK dengan alat bantu dan kit pengembangan serta kompiler dan sebagainya, dan kemudian memiliki runtime. Runtime tidak memiliki hal-hal "buat aplikasi", itu hanya memiliki "jalankan aplikasi". Saat ini tidak ada SDK untuk ARM jadi itu batasan bahwa kami (agak elegan) bekerja dengan file build multistage. Namun, meskipun ada SDK untuk ARM, kami tetap ingin menggunakan Dockerfile seperti ini karena lebih efisien dengan ruang dan membuat gambar lebih kecil.

Mari kita hancurkan ini. Ada dua tahap. FROM pertama adalah gambar SDK yang membuat kode. Kami sedang melakukan build di dalam Docker - cara yang bagus dan andal untuk melakukan build.

KIAT PRO: Docker pintar membuat gambar perantara dan melakukan pekerjaan paling sedikit , tapi itu berguna jika kita (penulis) melakukan hal yang benar juga untuk membantunya.

Misalnya, lihat di mana kita MENYALIN .csproj dan kemudian melakukan "pemulihan dotnet"? Seringkali Anda akan melihat orang melakukan "COPY .." dan kemudian melakukan pemulihan. Itu tidak memungkinkan Docker untuk mendeteksi apa yang berubah dan pada akhirnya Anda akan membayar untuk pemulihan di SETIAP BUILD.

Dengan membuat dua langkah ini - salin proyek, pulihkan, salin kode, ini berarti langkah perantara "pemulihan dotnet" Anda akan di-cache oleh Docker dan semuanya akan JAUH lebih cepat.

Setelah Anda membangun, Anda akan melakukan publikasi. Jika Anda mengetahui tujuan seperti yang saya lakukan (linux-arm), Anda dapat melakukan publikasi RID (runtime id) yang mandiri dengan -r linux-arm (atau debian, atau apa pun) dan Anda akan mendapatkan self- berisi versi aplikasi Anda.

Jika tidak, Anda cukup memublikasikan kode aplikasi dan menggunakan gambar runtime .NET Core untuk menjalankannya. Karena saya menggunakan build mandiri lengkap untuk gambar ini, akan berlebihan jika JUGA menyertakan runtime .NET. Jika Anda melihat hub Docker untuk Microsoft/dotnet Anda akan melihat gambar yang disebut "deps" untuk "dependensi." Itu adalah gambar yang berada di atas debian yang menyertakan hal-hal yang perlu dijalankan .NET - tetapi bukan .NET itu sendiri.

Tumpukan gambar umumnya terlihat seperti ini (misalnya)

  • DARI debian:stretch
  • DARI microsoft/dotnet:2.0-runtime-deps
  • DARI microsoft/dotnet:2.0-runtime

Jadi, Anda memiliki gambar dasar, dependensi, dan runtime .NET Anda. Gambar SDK akan menyertakan lebih banyak barang karena perlu membuat kode. Sekali lagi, itu sebabnya kami menggunakannya untuk gambar "sebagai pembuat" dan kemudian menyalin hasil kompilasi dan letakkan di gambar runtime lain. Anda mendapatkan yang terbaik dari semua dunia.

FROM microsoft/dotnet:2.0-sdk as builder  

RUN mkdir -p /root/src/app/aspnetcoreapp
WORKDIR /root/src/app/aspnetcoreapp

#copy just the project file over
# this prevents additional extraneous restores
# and allows us to re-use the intermediate layer
# This only happens again if we change the csproj.
# This means WAY faster builds!
COPY aspnetcoreapp.csproj .
#Because we have a custom nuget.config, copy it in
COPY nuget.config .
RUN dotnet restore ./aspnetcoreapp.csproj

COPY . .
RUN dotnet publish -c release -o published -r linux-arm

#Smaller - Best for apps with self-contained .NETs, as it doesn't include the runtime
# It has the *dependencies* to run .NET Apps. The .NET runtime image sits on this
FROM microsoft/dotnet:2.0.0-runtime-deps-stretch-arm32v7

#Bigger - Best for apps .NETs that aren't self-contained.
#FROM microsoft/dotnet:2.0.0-runtime-stretch-arm32v7

# These are the non-ARM images.
#FROM microsoft/dotnet:2.0.0-runtime-deps
#FROM microsoft/dotnet:2.0.0-runtime

WORKDIR /root/
COPY --from=builder /root/src/app/aspnetcoreapp/published .
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000/tcp
# This runs your app with the dotnet exe included with the runtime or SDK
#CMD ["dotnet", "./aspnetcoreapp.dll"]
# This runs your self-contained .NET Core app. You built with -r to get this
CMD ["./aspnetcoreapp"]

Perhatikan juga bahwa saya memiliki nuget.config khusus, jadi jika Anda melakukannya juga, Anda harus memastikan bahwa itu tersedia pada waktu pembuatan agar dotnet restore mengambil semua paket.

Saya telah menyertakan dengan mengomentari sekelompok FROM di tahap kedua. Saya hanya menggunakan ARM, tapi saya ingin Anda melihat yang lain.

Setelah kami memiliki kode yang kami buat disalin ke gambar runtime kami, kami mengatur variabel lingkungan kami sehingga semua kami mendengarkan di port 5000 secara internal (ingat itu dari atas?) Kemudian kami menjalankan aplikasi kami. Perhatikan bahwa Anda dapat menjalankannya dengan "dotnet foo.dll" jika Anda memiliki runtime, tetapi jika Anda seperti saya dan menggunakan build mandiri, maka Anda cukup menjalankan "foo."

Singkatnya:

  • Buat dengan FROM microsoft/dotnet:2.0-sdk sebagai pembuat
  • Salin hasilnya ke waktu proses
  • Gunakan runtime FROM yang tepat untuk Anda
    • Arsitektur CPU yang benar?
    • Menggunakan .NET Runtime (biasa) atau menggunakan build mandiri (kurang begitu)
  • Mendengarkan di port kanan (jika aplikasi web)?
  • Menjalankan aplikasi Anda dengan sukses dan benar?
  • Apakah Anda memiliki .dockerignore? Sangat penting untuk .NET Builds, karena Anda tidak ingin menyalin /obj, /bin, dll, tetapi Anda ingin /published.
    obj/
    bin/
    !published /

Mengoptimalkan sedikit lagi

Ada beberapa alat "Pemangkasan Pohon" pra-rilis yang dapat melihat aplikasi Anda dan menghapus kode dan biner yang tidak Anda panggil. Saya juga menyertakan Microsoft.Packaging.Tools.Trimming untuk mencobanya dan mendapatkan lebih banyak kode yang tidak digunakan dari gambar akhir saya hanya dengan menambahkan paket ke proyek saya.

Step 8/14 : RUN dotnet publish -c release -o published -r linux-arm /p:LinkDuringPublish=true
---> Running in 39404479945f
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Trimmed 152 out of 347 files for a savings of 20.54 MB
Final app size is 33.56 MB
aspnetcoreapp -> /root/src/app/aspnetcoreapp/bin/release/netcoreapp2.0/linux-arm/aspnetcoreapp.dll
Trimmed 152 out of 347 files for a savings of 20.54 MB
Final app size is 33.56 MB

Jika Anda menjalankan riwayat buruh pelabuhan pada gambar akhir Anda, Anda dapat melihat dengan tepat dari mana ukurannya berasal. Jika/ketika Microsoft beralih dari gambar dasar Debian ke gambar Alpine, ini akan menjadi lebih kecil.

C:\Users\scott\Desktop\k8s for pi\aspnetcoreapp>docker history c60
IMAGE CREATED CREATED BY SIZE COMMENT
c6094ca46c3b 3 minutes ago /bin/sh -c #(nop) CMD ["dotnet" "./aspnet... 0B
b7dfcf137587 3 minutes ago /bin/sh -c #(nop) EXPOSE 5000/tcp 0B
a5ba51b91d9d 3 minutes ago /bin/sh -c #(nop) ENV ASPNETCORE_URLS=htt... 0B
8742269735bc 3 minutes ago /bin/sh -c #(nop) COPY dir:cc64bd3b9bacaeb... 56.5MB
28c008e38973 3 minutes ago /bin/sh -c #(nop) WORKDIR /root/ 0B
4bafd6e2811a 4 hours ago /bin/sh -c apt-get update && apt-get i... 45.4MB
<missing> 3 weeks ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:8b7cf813a113aa2... 85.7MB

Inilah evolusi Dockerfile saya saat saya membuat perubahan dan hasil akhirnya semakin kecil. Sepertinya 45 MB dipangkas dengan sedikit kerja atau sekitar 20% lebih kecil.

C:\Users\scott\Desktop\k8s for pi\aspnetcoreapp>docker images | find /i "aspnetcoreapp"
shanselman/aspnetcoreapp 0.5 c6094ca46c3b About a minute ago 188MB
shanselman/aspnetcoreapp 0.4 083bfbdc4e01 12 minutes ago 196MB
shanselman/aspnetcoreapp 0.3 fa053b4ee2b4 About an hour ago 199MB
shanselman/aspnetcoreapp 0.2 ba73f14e29aa 4 hours ago 207MB
shanselman/aspnetcoreapp 0.1 cac2f0e3826c 3 hours ago 233MB

Nanti saya akan membuat posting blog di mana saya menempatkan aplikasi web ASP.NET Core standar ini ke dalam Kubernetes menggunakan deskripsi YAML ini dan menskalakannya di Raspberry Pi. Saya belajar banyak! Terima kasih kepada Alex Ellis dan Glenn Condron dan Jessie Frazelle atas waktunya!

Sponsor: Buat aplikasi Web yang andal untuk mengelola setiap langkah siklus hidup dokumen dengan DocuVieware HTML5 Viewer dan Document Management Kit. Periksa demo kami untuk memperoleh, memindai, mengedit, membubuhi keterangan 100+ format, dan menyesuaikan UI Anda!


Docker
  1. Cara Menggunakan Dockerfile untuk Membangun Gambar Docker

  2. Cara melakukan perubahan pada gambar Docker

  3. Menjalankan aplikasi ASP.NET Core mandiri di Ubuntu

  1. Pengantar Singkat Untuk Dockerfile

  2. Ekstrak File Dari Gambar Docker?

  3. Cara Memodifikasi Gambar Docker

  1. Cara Menjalankan Aplikasi .NET di Docker

  2. Apa itu Manifes Gambar Docker?

  3. Berbagi Gambar Docker di Docker Hub