Siapa yang tidak pernah ragu-ragu sama ada mereka mencipta imej Docker yang betul untuk aplikasi mereka? Nah, saya telah mengalami keraguan ini beberapa kali dan saya hampir selalu tidak tahu sama ada saya melakukannya dengan betul atau salah.
Jadi dalam artikel ini, kami akan meneroka amalan lanjutan untuk mencipta imej Docker yang cekap dan dioptimumkan untuk aplikasi Go anda. Kami akan membandingkan pendekatan yang berbeza, seperti menggunakan imej asas alpine dan scratch, dan membincangkan faedah setiap satu, dengan kod contoh dan analisis prestasi.
Pertama, mari kita wujudkan struktur projek tipikal untuk aplikasi Go dalam kontena.
Sebagai contoh, saya menggunakan aplikasi ini yang merupakan pemendek URL:
url_shortener ├── cmd │ └── main.go ├── internal │ ├── monitoring │ │ └── prometheus.go │ ├── server │ │ └── server.go │ └── shortener │ ├── model.go │ ├── repository.go │ ├── service.go │ └── service_test.go ├── pkg │ ├── api │ │ └── shortener │ │ ├── handler.go │ │ └── handler_integration_test.go │ └── utils │ └── base62 │ ├── hash.go │ └── hash_test.go ├── Dockerfile ├── Dockerfile.alpine ├── Dockerfile.golang ├── README.md ├── compose.yml ├── go.mod ├── go.sum └── prometheus.yml
Apa yang segelintir orang tahu ialah kita tidak memerlukan imej "lengkap" yang dijalankan dalam pengeluaran. Contohnya, Ubuntu dengan semua pakej, sumber, sambungan dan SDK untuk bahasa kita. Kami hanya boleh membina apl kami dalam sistem dengan SDK dan kemudian menyalin binaan ke imej yang lebih kecil dan dioptimumkan yang hanya akan menjalankan binaan itu. Dan di situlah Berbilang Peringkat masuk.
Dalam Fail Docker, anda boleh menentukan berbilang peringkat binaan, setiap satu bermula dengan pernyataan FROM. Peringkat pertama boleh digunakan untuk menyusun kod, memasang kebergantungan, menjalankan ujian, dsb. Dalam peringkat seterusnya, anda boleh menyalin hanya artifak yang diperlukan (seperti binari yang disusun) ke imej akhir, membuang semua yang tidak diperlukan untuk menjalankan aplikasi.
# syntax=docker/dockerfile:1 # Build stage FROM golang:1.22-alpine AS builder WORKDIR /app COPY . . RUN go mod download RUN go build -o url-shortener ./cmd # Final stage FROM alpine:latest WORKDIR /app COPY --from=builder /app/url-shortener . CMD ["./url-shortener"]
Sialan Rafa, tetapi apa yang anda lakukan dengan "dua imej ini"? Mula-mula saya menggunakan imej sebagai pembina, di mana kami mencipta aplikasi boleh laku:
Peringkat Pertama (Peringkat binaan):
Pada masa itu, saya menggunakan imej yang lebih kecil yang hanya akan menjalankan boleh laku ini yang kami hasilkan dalam langkah pertama:
Peringkat Kedua (Peringkat Akhir):
Jika kami ingin mengesahkan apa yang sebenarnya berlaku, dalam Docker Desktop terdapat kemungkinan untuk menganalisis hierarki imej. Di dalam kita boleh lihat apa yang dia gunakan:
Kini kami juga boleh menganalisis saiz imej yang baru kami hasilkan ini, dalam kes ini url-shortener:alpine iaitu ~30mb:
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE url-shortener alpine aa99d6a2c028 3 minutes ago 29.9MB
Alpine ialah pengedaran Linux yang minimalis, selamat dan ringan, digunakan secara meluas dalam persekitaran kontena kerana kecekapan dan kesederhanaannya. Ia menyediakan asas yang kukuh untuk membina aplikasi berskala tanpa overhed pengedaran Linux lain yang lebih berat.
Beberapa kelebihan menggunakan Alpine dalam apl kami terutamanya dikaitkan dengan 3 tiang ini:
Baiklah, tetapi bagaimana jika saya menggunakan versi SDK yang sama, dalam kes ini golang:1.22-alpine. Seberapa besar aplikasi saya?
REPOSITORY TAG IMAGE ID CREATED SIZE url-shortener golang-alpine d615d75c3aff 25 minutes ago 251MB
Nah, dalam kes ini, kami mendapat imej dengan ~250mb... Walaupun dibandingkan dengan alpine, kami hanya mencapai ~30mb, ia sudah menjadi perbezaan yang besar. Dan bolehkah ia dipertingkatkan lagi?
Jawapannya YA, dan mari kita masuk ke butirannya
Scratch ialah imej istimewa dan sangat minimalis dalam Docker. Ia sebenarnya imej asas yang paling mudah dan paling kosong yang boleh anda gunakan. Ia sama sekali tidak mengandungi apa-apa: tiada sistem pengendalian, tiada perpustakaan, tiada alatan — ia benar-benar bekas kosong.
Essa abordagem minimalista traz benefícios significativos, especialmente em termos de segurança. Ao usar Scratch, você minimiza drasticamente a superfície de ataque, já que não há pacotes ou ferramentas adicionais que possam introduzir vulnerabilidades. Seu contêiner contém apenas o essencial para a execução do aplicativo, garantindo um ambiente imutável e previsível em qualquer situação.
# syntax=docker/dockerfile:1 # Build stage FROM golang:1.22-alpine AS builder WORKDIR /app COPY . . RUN go mod download RUN go build -o url-shortener ./cmd # Final stage with Scratch FROM scratch WORKDIR /app COPY --from=builder /app/url-shortener . CMD ["./url-shortener"]
E o resultado após criar as 3 imagens, nosso ranking de menor imagem ficou assim:
O Scratch conseguiu baixar mais alguns megas no tamanho final de nossa aplicação. Isso impacta no tamanho de arquivos transferidos pela rede, hoje algumas empresas cobram pela banda que trafegamos dentro dos servidores, e também pode influenciar em nosso Horizontal Scaling da aplicação.
Deixei os 3 Dockerfiles dentro do repositório do github caso você queira testar em seu próprio pc ?
A resposta mais tranquila para essa é "quase sempre", uma dica de cara é: ele vai muito bem com linguagens como Go, Rust, ou C/C++. Mas qui estão alguns pontos para levar em consideração na hora de escolher se deve ou não usar o scratch:
Usar o cache do Docker para otimizar o tempo de build é uma técnica essencial para evitar recompilar ou baixar dependências desnecessariamente em cada build. O Docker armazena em cache as camadas de cada etapa do Dockerfile, reutilizando-as sempre que possível.
Em projetos Go, baixar dependências com go mod download pode ser um processo demorado, especialmente se houver muitas dependências. Se você recompilar todas as dependências em cada build, isso aumenta significativamente o tempo de build.
Ao copiar apenas os arquivos go.mod e go.sum em uma etapa separada antes de copiar o código-fonte completo, você permite que o Docker use o cache dessa etapa se os arquivos go.mod e go.sum não tiverem mudado. Veja como fica nosso Docker file com as mudanças:
# syntax=docker/dockerfile:1 # Build stage FROM golang:1.22-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN go build -o url-shortener ./cmd # Final stage FROM scratch WORKDIR /app COPY --from=builder /app/url-shortener . CMD ["./url-shortener"]
Só de fazer esta pequena mudança já ganhamos dois pontos bem interessantes quando se trata de desenvolvimento de software, que são:
Menor tempo de build: Se não houver alterações nos arquivos go.mod e go.sum, o Docker reutiliza o cache, evitando o download das dependências e economizando tempo.
Eficiência no CI/CD: Em pipelines de integração contínua, essa técnica reduz o tempo de execução dos pipelines, aumentando a eficiência do desenvolvimento e entrega.
Então bora usar isso a nosso favor no dia-a-dia :)
Docker Scout é uma ferramenta da Docker integrada ao Docker Desktop que analisa suas imagens para identificar vulnerabilidades de segurança. Ele fornece insights sobre as dependências presentes em suas imagens e alerta sobre possíveis problemas, permitindo que você tome medidas corretivas antes de implantar suas aplicações.
Por que é importante? Manter suas imagens Docker seguras é fundamental para proteger suas aplicações contra ataques e exploração de vulnerabilidades. O Docker Scout automatiza o processo de análise, tornando mais fácil manter suas imagens seguras e atualizadas.
O Scout funciona praticamente com 2 passos, ele examina a imagem Docker, mapeia todas as dependências incluídas na imagem e verifica essas dependências em uma base de dados de vulnerabilidades conhecidas. Por fim, classifica as vulnerabilidades encontradas por severidade e fornece recomendações para corrigir ou mitigar os problemas.
Dan dengan cara ini, kami akan mempunyai pencegahan proaktif yang akan mengenal pasti dan membetulkan kelemahan sebelum imej digunakan dalam pengeluaran, membantu melindungi daripada kemungkinan eksploitasi keselamatan dan kami juga memperoleh kecekapan operasi, apakah yang saya maksudkan dengan itu? Kami boleh mengautomasikan analisis kerentanan, membenarkan DevOps atau pasukan keselamatan menumpukan pada tindakan pembetulan dan bukannya penyiasatan manual.
Dengan amalan yang telah kami terokai, anda kini mempunyai laluan yang jelas untuk mencipta imej Docker untuk aplikasi Go anda menggunakan teknik seperti Binaan Berbilang Peringkat, yang mengurangkan saiz imej, memilih imej asas seperti alpine atau scratch untuk meningkatkan keselamatan dan. kecekapan, dan dengan menggunakan Pengakap Docker untuk memantau kelemahan, anda boleh memastikan aplikasi anda berjalan dengan cekap dan selamat.
Amalan ini bukan sahaja meningkatkan prestasi teknikal, tetapi juga membawa manfaat langsung kepada kehidupan harian anda dan kepada syarikat, menjimatkan masa dan sumber.
Jadi pada kali seterusnya anda membina imej Docker, ingatlah strategi ini. Gunakannya dan perhatikan hasilnya. ?
Atas ialah kandungan terperinci Go + Docker: Cara mencipta imej Docker terbaik untuk aplikasi Golang. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!