Skip to content

Docker 的总结与使用之 Dockerfile(二)

Published: at 00:00

前言

《Docker 的总结与使用之Docker(一)》

说明

一般情况下,我们可以使用 Dockerfile 来进行镜像的构建。流程是这样的:

  1. 获取到基础镜像
  2. 编写一个 Dockerfile 文件
  3. 使用 docker build 命令进行构建

使用

指令介绍

指令说明
FROM基础镜像,从哪个镜像开始构建
MAINTAINER作者信息,弃用
LABEL镜像元信息,KV 形式,比如作者信息
COPY从宿主机复制文件到镜像里
ADD从宿主机复制文件到镜像里,区别于 COPY 会对 tar 包解压
WORKDIR设置工作目录,相当于执行 CD
ENV设置镜像里的环境变量
ARG构建过程指定的环境变量
USER启动容器的用户
RUN构建镜像时执行的命令,一般执行安装环境相关的命令
CMD容器启动后的执行的命令,可被 docker run 覆盖
ENTRYPOINT容器启动后默认运行程序或命令,不可被 docker run 覆盖
EXPOSE暴露容器里的端口
VOLUME将宿主机的目录挂载到容器里,为了低耦合,一般不用
ONBUILD触发器,当该镜像被用作另一个构建过程的基础时
STOPSIGNAL发送给容器以退出的系统调用信号
HEALTHCHECK周期性检查容器健康状态的命令
SHELL覆盖 Docker 中默认的 shell

单阶段构建

说明

单阶段构建是指整个构建过程只需要在一个基础镜像上构建就可以完成。

构建 Vue 相关镜像示例
  1. 创建演示项目
pnpm create vite@latest demo
cd demo
  1. 获取基础镜像
$ docker pull node:16.18.0
  1. 编写 Dockerfile 文件
$ vim ./Dockerfile
FROM node:16.18.0
LABEL author=hwsdien
WORKDIR /www
COPY . .
RUN npm config set registry http://mirrors.cloud.tencent.com/npm/
RUN npm install -g pnpm@next-7
RUN pnpm install
EXPOSE 5173
CMD ["pnpm", "dev", "--host", "0.0.0.0"]
  1. 执行 build
$ docker build -t hwsdien/yhz-vue:v1.0.0 .
  1. 运行 & 测试
$ docker run -tid --name test-vue -p 8080:5173 hwsdien/yhz-vue:v1.0.0

$ curl http://127.0.0.1:8080
<!doctype html>
<html lang="en">
  <head>
    <script type="module" src="/@vite/client"></script>

    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue + TS</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>
构建 Golang 相关镜像示例
  1. 创建演示项目 这里使用 echo 框架进行演示,创建 go 项目
$ go mod init demo

创建 main.go 文件

package main

import (
  "github.com/labstack/echo/v4"
  "github.com/labstack/echo/v4/middleware"
  "net/http"
)

func main() {
  // Echo instance
  e := echo.New()

  // Middleware
  e.Use(middleware.Logger())
  e.Use(middleware.Recover())

  // Routes
  e.GET("/", hello)

  // Start server
  e.Logger.Fatal(e.Start(":1323"))
}

// Handler
func hello(c echo.Context) error {
  return c.String(http.StatusOK, "Hello, World!")
}
  1. 获取基础镜像
$ docker pull golang:1.22.0-alpine
  1. 编写 Dockerfile 文件
$ vim ./Dockerfile
FROM golang:1.22.0-alpine
LABEL author="hwsdien"
WORKDIR /www
COPY . .
RUN go env -w GO111MODULE=on
RUN go env -w GOPROXY=https://goproxy.cn,direct
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux go build -o demo
EXPOSE 1323
CMD ["./demo"]
  1. 执行 build
$ docker build -t hwsdien/yhz-golang:v1.0.0 .
  1. 运行 & 测试
$ docker run -tid --name test-golang -p 8088:1323 hwsdien/yhz-golang:v1.0.0

$ curl http://127.0.0.1:8088
构建 Python 相关镜像示例
  1. 创建演示项目 这里使用 fastapi 进行演示,创建 main.py 文件,内容如下:

from typing import Union

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}
  1. 获取基础镜像
$ docker pull python:3.12.2-alpine

# 尽量使用 alpine 版本,因为空间占用极少
# 这里可以看到非 alpine 版本有 1G 多
$ docker images | grep python
python                         3.12.2          d8be44680b2e   3 weeks ago      1.02GB
python                         3.12.2-alpine   80f904359cf6   3 weeks ago      56.5MB
  1. 编写 Dockerfile 文件
$ vim ./Dockerfile
FROM python:3.12.2-alpine
LABEL author=hwsdien
WORKDIR /www
COPY . .
RUN pip install fastapi -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN pip install "uvicorn[standard]" -i https://pypi.tuna.tsinghua.edu.cn/simple
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--reload"]
  1. 执行 build
$ docker build -t hwsdien/yhz-python:v1.0.0 .
  1. 运行 & 测试
$ docker run -tid --name test-python -p 8081:8000 hwsdien/yhz-python:v1.0.0

$ curl http://127.0.0.1:8081

多阶段构建

说明

多阶段是指整个构建过程需要依赖多个基础镜像,每个阶段需要依赖上个阶段构建的产物,比如某个java项目,第一个阶段构建打包 jar 文件,第二个阶段运行第一个阶段的 jar 文件。

构建 Nginx + Vue 镜像
  1. 创建演示项目
pnpm create vite@latest demo
cd demo
  1. 获取基础镜像
$ docker pull node:16.18.0
$ docker pull nginx:latest
  1. 编写 Nginx 的配置文件(nginx.conf)
$ cat ./nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
        worker_connections 768;
}

http {
        sendfile on;
        tcp_nopush on;
        types_hash_max_size 2048;
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
        gzip on;

        server {
                listen       80;
                server_name  localhost;

                location / {
                        root   /www;
                        index  index.html;
                        try_files $uri $uri/ /index.html;
                }

                error_page   500 502 503 504  /50x.html;
                location = /50x.html {
                        root   /www;
                }
        }
}

  1. 编写 Dockerfile 文件
$ vim ./Dockerfile
FROM node:16.18.0
LABEL author="hwsdien"
WORKDIR /app
COPY . .
RUN npm config set registry http://mirrors.cloud.tencent.com/npm/
RUN npm install -g pnpm@next-7
RUN pnpm install & pnpm build

FROM nginx:latest
RUN  mkdir /www
COPY --from=0 /app/dist /www
COPY nginx.conf /etc/nginx/conf.d/www.conf
  1. 执行 build
$ docker build -t hwsdien/yhz-nginx-vue:v1.0.0 .
  1. 运行 & 测试
$ docker run -tid --name test-nginx -p 8082:80 hwsdien/yhz-nginx-vue:v1.0.0

$ curl http://127.0.0.1:8082
<!doctype html>
<html lang="en">
  <head>
    <script type="module" src="/@vite/client"></script>

    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue + TS</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>