Trong bài viết này, chúng ta sẽ tìm hiểu 3 cách tối ưu: Layer Caching, dockerignore, và multi-stage
Docker layer caching
Docker layer caching (DLC) là một tính năng rất quan trọng giúp giảm thời gian của quá trình build bằng cách tận dụng những layer đã được build từ lần trước đó.
Để có thể tận dụng tối đa tính năng này, chúng ta cần sắp xếp lại và tách lệnh build sao cho phần lệnh ít thay đổi sẽ nằm ở trên, phần thay đổi thường xuyên sẽ nằm ở dưới.
Quay lại với ví dụ ExpressJs, giả sử chúng ta thêm 1 dòng console trong source code (Xem lại ví dụ ở Part 1)
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Nei hou!')
})
console.log("test");
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
Quá trình build
$ docker build -t alpine-test .
Sending build context to Docker daemon 2.43MB
Step 1/5 : FROM node:alpine
---> 5e67b1710572
Step 2/5 : WORKDIR /usr/app
---> Using cache
---> 4f036c778fe7
Step 3/5 : COPY ./ /usr/app/
---> f7a6b9681a06
Step 4/5 : RUN npm install
---> Running in 41ab0bba5814
up to date, audited 58 packages in 842ms
7 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
Removing intermediate container 41ab0bba5814
---> 13605717f2ac
Step 5/5 : CMD ["npm", "start"]
---> Running in fdf9ba2a93e0
Removing intermediate container fdf9ba2a93e0
---> 985b206362eb
Successfully built 985b206362eb
Successfully tagged alpine-test:latest
Chú ý là từ đoạn image 4f036c778fe7 trở lên trên, Docker daemon sẽ lấy từ cache. Bắt đầu từ step 3, image sẽ được tạo mới thay vì lấy từ cache. Rất hợp lý vì mình đã thay đổi source code.
Do vậy, trong quá trình build, chúng ta sẽ đưa các thành phần ít thay đổi lên trên.
Sử dụng .dockerignore
File .dockerignore giúp bạn định nghĩa những file hoặc thư mục mà bạn cần bỏ qua để build image. Việc này giúp giảm kích thước Docker image và tăng tốc độ quá trình build image. Dưới đây là cú pháp cho file .dockerignore:pattern:
{ term }
term:
'*' matches any sequence of non-Separator characters
'?' matches any single non-Separator character
'[' [ '^' ] { character-range } ']'
character class (must be non-empty)
c matches character c (c != '*', '?', '\\', '[')
'\\' c matches character c
character-range:
c matches character c (c != '\\', '-', ']')
'\\' c matches character c
lo '-' hi matches character c for lo <= c <= hi
additions:
'**' matches any number of directories (including zero)
'!' lines starting with ! (exclamation mark) can be used to make exceptions to exclusions
'#' lines starting with this character are ignored: use it for comments
Dockerignore cho Angular:
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode
Ví dụ file dockerignore cho asp.net core
# Created by https://www.gitignore.io/api/csharp
### Csharp ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/
tools/Cake.CoreCLR
.vscode
tools
.dotnet
Dockerfile
# .env file contains default environment variables for docker
.env
.git/
Multi Stage
Chúng ta sẽ minh họa bằng App Angular. Khác với ExpressJs, Angular cần được build và như vậy sẽ dễ hình dung hơn. Thay vì sử dụng NodeJs để host website, chúng ta sử dụng NGINX.
NGINX là một web server mạnh mẽ mã nguồn mở. Nginx sử dụng kiến trúc đơn luồng, hướng sự kiện vì thế nó hiệu quả hơn Apache server. Nó cũng có thể làm những thứ quan trọng khác, chẳng hạn như load balancing, HTTP caching, hay sử dụng như một reverse proxy.
Để hiển thị Syntax Highlighter trong Visual Studio Code, bạn cài đặt extension NGINX: ext install vscode-ngin.
Trong Terminal, tạo project Hello-World bằng cách
ng new hello-world
Tạo Dockerfile
Chúng ta sẽ có 2 stage để build 1 application Angular:
- Stage 1: Sử dụng base image Node để install packages, copy file thư mục output
- Stage 2: Sử dụng 1 base image v2 dùng Nginx.
Do ứng dụng Angular tương đối nặng, và đòi hỏi cần build typescript, nên chúng ta cần chuẩn bị file .dockerignore để loại bỏ bớt 1 số folder như /nodemodules, .vscode...
Ngoài ra để cấu hình nginx, chúng ta xây dựng file nginx.config.
Các bạn lưu ý file Dockerfile, .dockerignore đều nằm ở vị trí ngang hàng với thư mục source.
📁 frontend
└── 📂 angular
└──📂 .vscode
└──📂 nodemodules
└──📂 *.*
└──📂 src
├──index.html
├──*.*
└──.dockerignore
└──Dockerfile
└──nginx.conf
└──package.json
└──package-lock.json
└──*.*
File .dockerignore
.git
/node_modules
.gitignore
/e2e
File nginx.config
events{}
http {
include /etc/nginx/mime.types;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
}
Trong file Dockerfile, chúng ta sử dụng 2 images:
node:18-alpine3.15: dùng để phục vụ cho install package, copy file, và build project.
nginx:1.23.1-alpine: dùng để host ứng dụng Angular
### STAGE 1: Build ###
FROM node:18-alpine3.15 AS build
ARG CONFIGURATION='production'
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
# Build the application
RUN npm run build -- --output-path=dist --configuration=$CONFIGURATION --output-hashing=all
### STAGE 2: Run ###
FROM nginx:1.23.1-alpine
# Remove default nginx website
RUN rm -rf /usr/share/nginx/html/*
# Copy nginx config file
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build /usr/src/app/dist /usr/share/nginx/html
# Start NgInx service
CMD ["nginx", "-g", "daemon off;"]
Giải thích quá trình build image
Ở đây, chúng ta sử dụng toàn bộ OS là Alpine. Nếu các bạn sử dụng node:latest thì sẽ dụng phiên bản Debian
Sau khi thực hiện việc copy package.json,chúng ta sẽ install package.
Rồi thực hiện quá trình publish ra folder dist
Các câu lệnh dùng để build, run và exec vào bash:docker build -t angular-demo .
docker run -d -p 3000:80 --name angular-demo angular-demo
docker exec -it angular-demo sh
Dung lượng file sau khi build:
angular-demo latest c35e7f6387b7 22 minutes ago 23.8MB
<none> <none> 20699e47bc8e 22 minutes ago 607MB
node 18-alpine3.15 ec9347a9b50f 4 days ago 167MB
nginx 1.23.1-alpine 804f9cebfdc5 4 weeks ago 23.5MB
Như vậy là chúng ta đã tối ưu được dung lượng file từ 607MB xuống còn 23.8MB
Hi vọng với bài viết này sẽ hữu ích với các bạn trong quá trình xây dựng build image.
Tham khảo
https://medium.com/the-agile-crafter/docker-image-optimization-from-1-16gb-to-22-4mb-53fdb4c53311
Docker Image Optimization Tools
Trả lờiXóaFollowing are some of the open-source tools that will help you optimize
Dive: It is an image explorer tool that helps you discover layers in the Docker & OCI containers images. Using dive, you can find ways to optimize your Docker images. Check out the Dive Github repo for more details.
Docker Slim: It helps you optimize your Docker images for security and size. Check out the Docker Slim Github repo for more details.