简单使用scratch镜像

1、编写go-demo项目

hello目录有main.go和go.mod文件

main.go文件: 

package main

import (
	"net/http"
    "fmt"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello world"))
	})
    fmt.Println("start server: http://127.0.0.1:8000")
	http.ListenAndServe("0.0.0.0:8000", nil)
}

go.mod文件:

module hello

go 1.21.6

编译成可执行文件:

# 修改go环境变量CGO_ENABLED设置为0,默认为1
# 详见:https://zhuanlan.zhihu.com/p/576103234
go env -w CGO_ENABLED='0'

# 编译项目
go build -o app main.go

查看文件:

 

2、构建镜像并运行

编写Dockerfile文件:

FROM scratch
COPY ./app /app
EXPOSE 8000
CMD ["/app"]

构建镜像:

docker build -t app:v1 .

查看镜像:

运行容器:

docker run --rm -p 8000:8000 app:v1

curl访问:

curl http://127.0.0.1:8000

参考:

https://docs.docker.com/build/building/base-images/

https://docs.docker.com/build/building/multi-stage/

3、分析docker文档的Dockerfile文件

源文件地址:docs/Dockerfile at main · docker/docs · GitHub

3.1、定义参数

# syntax=docker/dockerfile-upstream:master
# check=skip=InvalidBaseImagePlatform

# ALPINE_VERSION sets the Alpine Linux version for all Alpine stages
ARG ALPINE_VERSION=3.20
# GO_VERSION sets the Go version for the base stage
ARG GO_VERSION=1.22
# HTML_TEST_VERSION sets the wjdp/htmltest version for HTML testing
ARG HTMLTEST_VERSION=0.17.0

alpine镜像版本:ALPINE_VERSION=3.20
go版本:GO_VERSION=1.22
htmltest版本:HTMLTEST_VERSION=0.17.0 

3.2、base阶段:基于golang:1.22镜像构建

# base is the base stage with build dependencies
FROM golang:${GO_VERSION}-alpine AS base
WORKDIR /src
RUN apk --update add nodejs npm git gcompat

工作目录:/src

apk --update add:命令用于安装一个或多个软件包,并在安装前更新软件包列表

安装或更新 nodejs、npm、git、gcompat软件

3.3、node阶段:基于base阶段构建

# node installs Node.js dependencies
FROM base AS node
COPY package*.json .
ENV NODE_ENV=production
RUN npm install

复制当前Dockerfile所在宿主机的package.json等文件 到 当前镜像的/src目录

设置环境变量NODE_ENV

npm install命令:根据package.json,安装依赖下载到node_modules目录

3.4、hugo阶段:基于base阶段构建

# hugo downloads and extracts the Hugo binary
FROM base AS hugo
ARG HUGO_VERSION=0.132.0
ARG TARGETARCH
WORKDIR /tmp/hugo
RUN wget -O "hugo.tar.gz" "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-${TARGETARCH}.tar.gz"
RUN tar -xf "hugo.tar.gz" hugo

hugo版本:HUGO_VERSION=0.132.0

工作目录:/tmp/hugo

使用wget下载hugo安装包,并使用tar命令解压

3.5、build-base阶段:基于base阶段构建

# build-base is the base stage for building the site
FROM base AS build-base
COPY --from=hugo /tmp/hugo/hugo /bin/hugo
COPY --from=node /src/node_modules /src/node_modules
COPY . .

复制hugo阶段的/tmp/hugo/hugo文件 到 当前镜像的/bin/hugo

复制node阶段的/src/node_modules文件 到 当前镜像的/src/node_modules

复制当前Dockerfile所在宿主机的当前文件 到 当前镜像的/src目录

3.6、dev阶段:基于build-base阶段构建

# dev is for local development with Docker Compose
FROM build-base AS dev

3.7、build阶段:基于build-base阶段构建

# build creates production builds with Hugo
FROM build-base AS build
# HUGO_ENV sets the hugo.Environment (production, development, preview)
ARG HUGO_ENV
# DOCS_URL sets the base URL for the site
ARG DOCS_URL
RUN hugo --gc --minify -d /out -e $HUGO_ENV -b $DOCS_URL

生成html文件:hugo --gc --minify -d /out -e $HUGO_ENV -b $DOCS_URL

hugo命令部分参数说明:

  --gc:enable to run some cleanup tasks (remove unused cache files) after the build

  --minify:minify any supported output format (HTML, XML etc.)

  -d, --destination string:filesystem path to write files to

  -e, --environment string:build environment

  -b, --baseURL string:hostname (and path) to the root, e.g. https://spf13.com/

3.8、lint阶段:基于davidanson/markdownlint-cli2镜像构建

# lint lints markdown files
FROM davidanson/markdownlint-cli2:v0.13.0 AS lint
USER root
RUN --mount=type=bind,target=. \
    /usr/local/bin/markdownlint-cli2 \
    "content/**/*.md" \
    "#content/engine/release-notes/*.md" \
    "#content/desktop/previous-versions/*.md"

--mount=type=bind,from=构建阶段或镜像名称,source=源路径,target=目标路径 

RUN --mount 

RUN --mount=type=bind 

https://blog.51cto.com/gugu/6085739 

3.9、test阶段:基于htmltest:0.17.0镜像构建

# test validates HTML output and checks for broken links
FROM wjdp/htmltest:v${HTMLTEST_VERSION} AS test
WORKDIR /test
COPY --from=build /out ./public
ADD .htmltest.yml .htmltest.yml
RUN htmltest

wjdp/htmltest:测试生成的HTML是否存在问题

工作目录:/test

复制build阶段的/out目录 到 当前镜像的/test/public目录

复制当前Dockerfile所在宿主机的.htmltest.yml文件 到 当前镜像的/test/.htmltest.yml

GitHub - wjdp/htmltest: :white_check_mark: Test generated HTML for problems 

3.10、update-modules阶段:基于build-base阶段构建

# update-modules downloads and vendors Hugo modules
FROM build-base AS update-modules
# MODULE is the Go module path and version of the module to update
ARG MODULE
RUN <<"EOT"
set -ex
if [ -n "$MODULE" ]; then
    hugo mod get ${MODULE}
    RESOLVED=$(cat go.mod | grep -m 1 "${MODULE/@*/}" | awk '{print $1 "@" $2}')
    go mod edit -replace "${MODULE/@*/}=${RESOLVED}";
else
    echo "no module set";
fi
EOT
RUN hugo mod vendor

hugo mod vendor:Vendor all module dependencies into the _vendor directory.

将依赖写入_vendor目录

Here-Documents

# syntax=docker/dockerfile:1
FROM debian
RUN <<EOT bash
  set -ex
  apt-get update
  apt-get install -y vim
EOT

set参数说明(Linux系统使用 man set 查看):

-e      Exit immediately if a pipeline (which may consist of a single simple command),  a subshell command enclosed in parentheses, or one of the  commands  executed  as part  of  a command list enclosed by braces (see SHELL GRAMMAR above) exits with a non-zero status.  The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in  a  && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !.  A trap on ERR, if set, is executed before the shell exits.  This option applies to the shell environment and each subshell environment separately (see COMMAND EXE‐CUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell. 

-x      After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of  PS4,  followed  by  the command and its expanded arguments or associated word list.

3.11、vendor阶段:基于scratch镜像构建

# vendor is an empty stage with only vendored Hugo modules
FROM scratch AS vendor
COPY --from=update-modules /src/_vendor /_vendor
COPY --from=update-modules /src/go.* /

复制update-modules阶段的/src/_vendor文件 到 当前镜像的/_vendor

复制update-modules阶段的/src/go.*文件 到 当前镜像的/

3.12、build-upstream阶段:基于build-base阶段构建

# build-upstream builds an upstream project with a replacement module
FROM build-base AS build-upstream
# UPSTREAM_MODULE_NAME is the canonical upstream repository name and namespace (e.g. moby/buildkit)
ARG UPSTREAM_MODULE_NAME
# UPSTREAM_REPO is the repository of the project to validate (e.g. dvdksn/buildkit)
ARG UPSTREAM_REPO
# UPSTREAM_COMMIT is the commit hash of the upstream project to validate
ARG UPSTREAM_COMMIT
# HUGO_MODULE_REPLACEMENTS is the replacement module for the upstream project
ENV HUGO_MODULE_REPLACEMENTS="github.com/${UPSTREAM_MODULE_NAME} -> github.com/${UPSTREAM_REPO} ${UPSTREAM_COMMIT}"
RUN hugo --ignoreVendorPaths "github.com/${UPSTREAM_MODULE_NAME}" -d /out

upstream_module_name、upstream_repo、upstream_commit

hugo部分参数说明:

  --ignoreVendorPaths string:ignores any _vendor for module paths matching the given Glob pattern

  -d, --destination string:filesystem path to write files to 

3.13、validate-upstream阶段:基于wjdp/htmltest:0.17.0镜像构建

# validate-upstream validates HTML output for upstream builds
FROM wjdp/htmltest:v${HTMLTEST_VERSION} AS validate-upstream
WORKDIR /test
COPY --from=build-upstream /out ./public
ADD .htmltest.yml .htmltest.yml
RUN htmltest

工作目录:/test

复制build-stream阶段的/out文件 到 当前镜像的/test/public

复制当前Dockerfile所在宿主机的.htmltest.yml文件 到 当前镜像的/test/.htmltest.yml

GitHub - wjdp/htmltest: :white_check_mark: Test generated HTML for problems 

3.14、unused-media阶段:基于alpine:3.20镜像构建

# unused-media checks for unused graphics and other media
FROM alpine:${ALPINE_VERSION} AS unused-media
RUN apk add --no-cache fd ripgrep
WORKDIR /test
RUN --mount=type=bind,target=. <<"EOT"
set -ex
./scripts/test_unused_media.sh
EOT

不使用缓存安装fd、ripgrep软件

工作目录:/test

3.15、path-warnings阶段:基于build-base阶段构建

# path-warnings checks for duplicate target paths
FROM build-base AS path-warnings
RUN hugo --printPathWarnings > /path-warnings.txt
RUN <<EOT
DUPLICATE_TARGETS=$(grep "Duplicate target paths" /path-warnings.txt)
if [ ! -z "$DUPLICATE_TARGETS" ]; then
    echo "$DUPLICATE_TARGETS"
    echo "You probably have a duplicate alias defined. Please check your aliases."
    exit 1
fi
EOT

hugo命令部分参数说明:

 --printPathWarnings:print warnings on duplicate target paths etc.

3.16、pagefind阶段:基于base阶段构建

# pagefind installs the Pagefind runtime
FROM base AS pagefind
ARG PAGEFIND_VERSION=1.1.0
COPY --from=build /out ./public
RUN --mount=type=bind,src=pagefind.yml,target=pagefind.yml \
    npx pagefind@v${PAGEFIND_VERSION} --output-path "/pagefind"

pagefind版本:1.1.0

复制build阶段的/out文件 到 当前镜像/src/public

npx pagefind@v1.1.0 --output-path "/pagefind":生成文件输出到/pagefind

Pagefind CLI configuration options | Pagefind — Static low-bandwidth search at scale 

3.17、index阶段:基于scratch镜像构建

# index generates a Pagefind index
FROM scratch AS index
COPY --from=pagefind /pagefind .

复制pagefind阶段的/pagefind文件 到 当前镜像 

3.18、test-go-redirects阶段:基于alpine:3.20镜像构建

# test-go-redirects checks that the /go/ redirects are valid
FROM alpine:${ALPINE_VERSION} AS test-go-redirects
WORKDIR /work
RUN apk add yq
COPY --from=build /out ./public
RUN --mount=type=bind,target=. <<"EOT"
set -ex
./scripts/test_go_redirects.sh
EOT

工作目录:/work

安装yq

复制build阶段的/out文件 到 当前镜像的/work/public

3.19、release阶段:基于scratch镜像构建

# release is an empty scratch image with only compiled assets
FROM scratch AS release
COPY --from=build /out /
COPY --from=pagefind /pagefind /pagefind

复制build阶段的/out文件 到 当前镜像的/

复制pagefind阶段的/pagefind文件 到 当前镜像的/pagefind

3.20、Dockerfile部分指令说明

https://docs.docker.com/reference/dockerfile/

1)FROM……AS……

Name your build stages

Use a previous stage as a new stage

2)COPY --from

Use an external image as a stage

3)--mount=type=bind

RUN --mount

RUN --mount=type=bind

https://blog.51cto.com/gugu/6085739

4)<<EOT

Here-Documents

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值