Chuyển đến nội dung chính

Docker: Khám phá quá trình build 1 image

Bài viết này gồm 2 phần. 

Phần 1, chúng ta sẽ khám phá bên trong container có những gì. Sau đó, chúng ta ngẫm nghĩ xem để build 1 file image, thay vì sử dụng template, chúng ta sẽ tự custom và build template mới.

Phần 2, chúng ta sẽ tìm cách optimize dung lượng file image.

Tạo 1 Docker image đơn giản

Trước khi bắt đầu, chúng ta sẽ xem lại các bước cơ bản để tạo 1 image


Trong Dockerfile, có thể chia ra làm 3 phần cơ bản:

  1. Sử dụng base image
  2. Install dependency packages
  3. Truyền tham số như thế nào để tạo container từ image
#Use an existing docker image as a base

#Download and install dependency

#Tell the image what to do when it starts
#as a container
Ý nghĩa các câu lệnh
FROM : Là base image để chúng ta tiến hành build một image mới trên image. Chỉ thị này phải được đặt trên cùng của Dockerfile
FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]


Vd: FROM ruby || ubuntu || mysql || mcr.microsoft.com/dotnet/sdk:6.0 AS build-env

RUN
Chỉ thị RUN dùng để chạy một lệnh nào đó trong quá trình build image và thường là các câu lệnh Linux.
Ví dụ, để chạy câu lệnh update đối với Ubuntu sẽ là RUN apt-get update -y còn đối với CentOS thì sẽ là Run yum update -y. Kết quả của câu lệnh sẽ được commit lại, kết quả commit đó sẽ được sử dụng trong bước tiếp theo của Dockerfile.

CMD : Sử dụng khi muốn thực thi các command trong quá trình build container mới từ image

Hello World bằng ExpressJs

Để run 1 ứng dụng ExpressJs, bạn cần:

  • 1 hệ điều hành
  • Cài đặt NodeJs
  • Cài đặt Express
  • Source code web application
  • Khởi động ứng dụng: npm start

Tạo file app.js

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
Tạo file package.json
{
    "dependencies": {
        "express": "*"
    },
    "scripts": {
        "start": "node app.js"
    }
}
Để build image Express, bạn tạo file Dockerfile có nội dung như sau:
# syntax=docker/dockerfile:1
FROM node:18.8

WORKDIR /usr/app
#Copy file and restore as distinct layers
COPY ./ /usr/app/
RUN npm install

#Default command
CMD ["npm", "start"]
Build Express image
docker build -t expressjs .
Output
Sending build context to Docker daemon   2.43MB
Step 1/5 : FROM node:18.8
18.8: Pulling from library/node
1671565cc8df: Pull complete
3e94d13e55e7: Pull complete
fa9c7528c685: Pull complete
53ad072f9cd1: Pull complete
d6b983117533: Pull complete
eac9917c3316: Pull complete
56b8d2414e53: Pull complete
8342b6d78d6f: Pull complete
52437043774d: Pull complete
Digest: sha256:a0a2fc4435b0c9ae7bec0a69b1279323a4a41c5a005581fbf30d39cd5777db37
Status: Downloaded newer image for node:18.8
 ---> ac3dcfe39c7e
Step 2/5 : WORKDIR /usr/app
 ---> Running in b8931910d7c3
Removing intermediate container b8931910d7c3
 ---> d6d9c8709983
Step 3/5 : COPY ./ /usr/app/
 ---> 1a615975d8ab
Step 4/5 : RUN npm install
 ---> Running in f22c94db38d6

up to date, audited 58 packages in 507ms

7 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Removing intermediate container f22c94db38d6
 ---> d4b3c1db3ee7
Step 5/5 : CMD ["npm", "start"]
 ---> Running in 3661bd98f384
Removing intermediate container 3661bd98f384
 ---> a45ba4b7be61
Successfully built a45ba4b7be61
Successfully tagged expressjs:latest
Trở lại Terminal, gõ lệnh:
docker images
Kết quả
REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
expressjs    latest    a45ba4b7be61   About a minute ago   993MB
node         18.8      ac3dcfe39c7e   9 days ago           991MB
Run container
docker run -p 1001:3000 -d expressjs
Để khám phá bên trong container, bạn gõ:
docker exec -it <container-id> /bin/bash
Dùng lệnh ls để liệt kê folder và file
/usr/app# ls
Dockerfile  app.js  node_modules  package-lock.json  package.json

Vậy ý nghĩa thực sự của dòng khai báo: WORKDIR là bạn khai báo folder. Nhưng folder đó nằm ở đâu. 

Tiếp tục, bạn gõ lệnh kiểm tra OS version:

cat /etc/os-release
Kết quả:
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Đây là phiên bản Debian release vào 9/7/2022. Hiện tại khi viết bài này là 3/9/2022. 

Vậy bản chất việc khai báo FROM là bạn khai báo OS kèm thư viện hỗ trợ (trong bài viết này là NodeJS 18.8)

Quay lại ví dụ bên trên, bạn quan sát các dòng output trong quá trình build và các images được liệt kê

Có 1 sự kì lạ là ở Step 1, chúng ta khai báo FROM NodeJs thì Docker tải image về. Và khi tìm hiểu sâu hơn thì đó không phải là 1 library mà là 1 Operating System đã được cài đặt NodeJs.

Về bản chất, Docker coi mỗi dòng lệnh ta khai báo ở trong Dockerfile như là 1 instruction - chỉ dẫn, các instruction RUN, COPY, ADD tạo ra các layer. 

Khi ta build image, Docker sẽ đọc từng dòng trong Dockerfile. Với mỗi chỉ dẫn, 1 container mới sẽ được tạo ra, và sau đó 1 image mới được tạo ra từ container đó.

Bạn có thể kiểm tra lại bằng lệnh: docker images -a


Ví dụ ở step 2
Status: Downloaded newer image for node:18.8
 ---> ac3dcfe39c7e
Step 2/5 : WORKDIR /usr/app
 ---> Running in b8931910d7c3
Removing intermediate container b8931910d7c3
 ---> d6d9c8709983
Chúng ta có image với TagId là ac3dcfe39c7e. Container b8931910d7c3 được tạo ra sau đó để thực hiện việc Thêm mới 1 folder và cd tới thư mục mới. Cuối cùng Container b8931910d7c3 được remove đi để tạo ra image mới ở bước tiếp theo.

Nếu thấy layer nào ko thay đổi, đã có từ những lần build trước thì Docker sẽ tận dụng lại.

Để kiểm tra quá trình tạo và xóa container, mở 2 màn hình bash

  • Bash 1: docker stats -a 
  • Bash 2: bạn thực hiện việc build Docker image.

Do vậy nếu chúng ta biết cách tổ chức Dockerfile, đưa các thành phần ít thay đổi lên trên, thành phần hay thay đổi xuống dưới thì sẽ tận dụng được tính năng tuyệt vời này và giảm đáng kể thời gian chờ build image.

Tham khảo

https://viblo.asia/p/tang-toc-do-build-va-toi-gian-docker-image-Eb85oODB52G 

https://iximiuz.com/en/posts/you-need-containers-to-build-an-image/

Nhận xét

  1. Bổ sung câu lệnh: RUN sleep 2 để làm chậm tiến trình build Docker image

    Trả lờiXóa

Đăng nhận xét

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.