惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog
T
Threatpost
N
News and Events Feed by Topic
C
Cybersecurity and Infrastructure Security Agency CISA
Cyberwarzone
Cyberwarzone
C
CXSECURITY Database RSS Feed - CXSecurity.com
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
AI
AI
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Security Latest
Security Latest
Scott Helme
Scott Helme
W
WeLiveSecurity
S
Schneier on Security
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园_首页
Forbes - Security
Forbes - Security
Simon Willison's Weblog
Simon Willison's Weblog
S
Security @ Cisco Blogs
The Register - Security
The Register - Security
H
Hacker News: Front Page
V
Visual Studio Blog
P
Privacy & Cybersecurity Law Blog
P
Privacy International News Feed
TaoSecurity Blog
TaoSecurity Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News | PayPal Newsroom
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google DeepMind News
Google DeepMind News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
C
CERT Recently Published Vulnerability Notes
Y
Y Combinator Blog
D
Docker
I
InfoQ
AWS News Blog
AWS News Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
Securelist
L
LINUX DO - 最新话题
阮一峰的网络日志
阮一峰的网络日志
Help Net Security
Help Net Security
G
GRAHAM CLULEY
G
Google Developers Blog
The Last Watchdog
The Last Watchdog
Hugging Face - Blog
Hugging Face - Blog
Blog — PlanetScale
Blog — PlanetScale
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Stack Overflow Blog
Stack Overflow Blog
I
Intezer

陈少文的网站

巨变与机遇的未来十年 Kubernetes 平台管理软件压力测试方案 使用镜像部署 Hexo 静态页面 终于等到你 - GitHub 镜像仓库服务(ghcr.io) 一起来学 Go --(6)Interface 一起来学 Go --(5)Goroutine 和 Channel 什么是函数式编程 如何在 Kubernetes 集群集成 Kata 柯里化与偏函数 使用 PyGithub 自动创建 Label 软件产品是团队能力的输出 Helm 2 、Helm 3 比较 IoT 变现 Kubernetes 中的 DNS 服务 国内的 Helm 镜像源 Harbor 使用自签证书支持 Https 访问 DevOps 工具链之 Prow 如何使用 kfctl 安装 Kubeflow VS Code 无法下载 Go 插件的工具包 工程师更应具有服务精神 你不知道的 Docker 使用技巧 使用 Docker 运行 Tensorflow 论中国 什么是左移 如何清空 Git 仓库全部历史记录 一禅小和尚 有风吹过厨房 时间的玫瑰 如何在 CentOS 安装 GPU 驱动 开发 Tips(19) 使用 Velero 备份 Kubernetes 集群 Kubernetes Cheat Sheet 开发 Tips(18) 如何构建一个 Java 工程 开发 Tips(17) KubeSpray 安装 Kubernetes 报错 ip in ansible_all_ipv4_addresses 基于 Kubernetes 和 Jenkins 搭建自动化测试系统 在 Kubernetes 上动态创建 Jenkins Slave 使用 Jenkins 进行服务拨测 开发 Tips(16) Kubernetes 签发 Ingress 证书及日常故障运维 Kubernetes 中 Deployment 的基本操作 Kubernetes 中的证书 如何使用 KubeBuilder 开发一个 Operator Kubernetes 1.6.0 安装问题汇总 镜像管理工具 -- Harbor 开发 Tips(15) Docker 如何拉取镜像 开发 Tips(14) 使用 Helm 安装 harbor 开发 Tips(13) 使用 S2I 构建云原生应用 在 Kubernetes 中使用 emptyDir、hostPath、localVolume 开发 Tips(12) 开发 Tips(11) 代码质量分析工具 SonarQube 使用 Kubeadm 安装 Kubernetes 集群 一起来学 Go --(4)常用函数 Kubernetes 中的 Ceph Kubernetes 之 Volumes Kubernetes 之 Labels、Selectors 开发 Tips(10) 开源正在重构商业模式 Kubernetes 之网络 Kubernetes 之 API 使用 Helm 和 Operator 快速部署 Prometheus Kubernetes 复杂有状态应用管理框架 -- Operator Kubernetes 的包管理器 -- Helm 一起来学 Go --(3)Go Modules 如何一步一步地优化博客方案 kubectl 实用指南 Kubernetes 中的基本概念 搭建远程 Kubernetes 开发环境 大公司和小公司的 ToB 思路 开发 Tips(9) Go 入门指南 一起来学 Go --(2)数据与逻辑结构 如何预防 Web 富文本中的 XSS 攻击 django-xss-cleaner 云工作时代 一起来学 Go --(1)背景与特点 SaaS 开发团队的不同阶段 你不知道的 Git 使用技巧 输出既服务 微服务设计 继续奔跑 开发 Tips(8) 从账户安全到二次验证 Django 性能之数据库查询优化 Django 性能之分库分表 敏捷开发之研发流程 打造一致性的团队 开发 Tips(7) Pytest 进阶学习之 Mock PaaS 部署之 buildpack Go 开发配置 领域输出才是 PaaS 的核心竞争力 Pytest 入门学习 开发 Tips(6) 如何使用 Jenkins、Docker、GitLab 搭建 Django 自动化部署流程
Daemon-less 镜像构建工具 - Kaniko
微信公众号 · 2020-12-11 · via 陈少文的网站

1. daemon-less 镜像构建工具

1.1 什么是 daemon-less 镜像构建工具

在 CICD 流程中,经常会涉及镜像构建,常规的做法是使用 Docker in Docker 或者 Docker out of Docker 进行构建。详情可以参考文档:如何在 Docker 中使用 Docker

实际上,为了避免垄断,促进行业发展,基于 Docker 的镜像格式,早就指定了统一的 OCI 镜像格式规范。也就是说,只需要通过 Dockerfile 得到一个符合 OCI 规范的镜像即可,并没有强制要求谁来做这件事。

daemon-less 的构建工具,可以不依赖于 Docker Daemon 进行构建镜像。这在 CICD 场景下,具有重要的意义。同时,Kubernetes 正在摆脱 Docker 的影响,构建更加开放的架构生态,CICD 需要与 Docker Daemon 解耦。

1.2 daemon-less 的优势

  • 免挂载 sock 文件

目前,实现 CRI 和 OCI 接口的运行时组件越来越多,例如 cri-o、containerd。这些运行时管理工具,并没有类似 /var/run/docker.sock 的文件用于挂载服务。daemon-less 的构建方式能够对接这些工具。

  • 更加安全

这些 daemon-less 工具,通常运行在 userspace ,而不是以 root 特权运行,提供更加安全的运行时。

  • 更适合 Kubernetes

通过挂载 /var/run/docker.sock 的方式,使用 Docker Daemon 构建镜像,是一种集中的构建方式。镜像的构建主要交给节点上的 Docker Daemon 来完成。而如果能直接将 Dockerfile 转换成镜像,更加适应 Kubernetes、Serverless 基础设施,构建规模和效率将得到提高。

1.3 相关的开源项目

  • Kaniko, Google 主导
  • Buildah, Red Hat 主导
  • Img, Jessie Frazelle 发起

从 Star 量上看,Buildah、Img 目前是 3K+,而 Kaniko 达到 7K+,下面以 Kaniko 为例行文。

2. Kaniko 的工作原理

如上图是 Kaniko 的工作原理图。Kaniko 执行器从 Dockerfile 构建镜像,并将其推送到镜像仓库。主要分为以下几步:

  • 根据 Dockerfile 中 FROM 描述,解压基础镜像的文件系统
  • 执行 Dockerfile 中的每条命令,在用户空间建立文件快照
  • 将变更的文件层添加到基础镜像中,更新镜像的元数据
  • 推送镜像

已知的问题

  • 不支持构建 Windows 镜像
  • kaniko 命令只能在官方镜像中运行,不支持其他 Docker 镜像
  • 不支持 Registry V1 接口

3. Kaniko Demo

3.1 测试 Demo 选择

这里选择的是 https://github.com/traefik/whoami 项目。访问该服务之后,接口会返回访问者的相关信息。

对项目的要求是,通过 Dockerfile 能够直接编译得到镜像。一共有两个验证点:

  • 能够构建镜像
  • 构建的镜像能够运行

3.2 在 Docker 上运行 Kaniko

  • 生成推送镜像的凭证
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export AUTH=$(echo -n YOUR_USERNAME:YOUR_PASSWORD | base64 )

cat > config.json <<-EOF
{
 "auths": {
  "https://index.docker.io/v1/": {
   "auth": "${AUTH}"
  }
 }
}
EOF
  • 构建镜像
1
2
3
4
5
docker run \
  --interactive -v `pwd`/config.json:/kaniko/.docker/config.json gcr.io/kaniko-project/executor:latest \
  --context git://github.com/traefik/whoami \
  --dockerfile Dockerfile \
  --destination=shaowenchen/kaniko-demo:v1
参数说明:
- context, 构建需要的上下文。支持多种格式,S3、本地目录、标准输入、Git 仓库等
- dockerfile, Dockerfile 路径
- destination, 构建后推送的镜像地址

在生产环境,可以配置缓存,用于加速镜像构建。

  • 查看日志

执行上一步的命令之后,可以看到如下输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
Enumerating objects: 17, done.
Counting objects: 100% (17/17), done.
Compressing objects: 100% (13/13), done.
Total 157 (delta 3), reused 12 (delta 3), pack-reused 140
INFO[0004] Resolved base name golang:1-alpine to builder
INFO[0004] Retrieving image manifest golang:1-alpine
INFO[0004] Retrieving image golang:1-alpine
INFO[0007] Retrieving image manifest golang:1-alpine
INFO[0007] Retrieving image golang:1-alpine
INFO[0010] No base image, nothing to extract
INFO[0010] Built cross stage deps: map[0:[/usr/share/zoneinfo /etc/ssl/certs/ca-certificates.crt /go/whoami/whoami]]
INFO[0010] Retrieving image manifest golang:1-alpine
INFO[0010] Retrieving image golang:1-alpine
INFO[0012] Retrieving image manifest golang:1-alpine
INFO[0012] Retrieving image golang:1-alpine
INFO[0015] Executing 0 build triggers
INFO[0015] Unpacking rootfs as cmd RUN apk --no-cache --no-progress add git ca-certificates tzdata make     && update-ca-certificates     && rm -rf /var/cache/apk/* requires it.
INFO[0035] RUN apk --no-cache --no-progress add git ca-certificates tzdata make     && update-ca-certificates     && rm -rf /var/cache/apk/*
INFO[0035] Taking snapshot of full filesystem...
INFO[0041] cmd: /bin/sh
INFO[0041] args: [-c apk --no-cache --no-progress add git ca-certificates tzdata make     && update-ca-certificates     && rm -rf /var/cache/apk/*]
INFO[0041] Running: [/bin/sh -c apk --no-cache --no-progress add git ca-certificates tzdata make     && update-ca-certificates     && rm -rf /var/cache/apk/*]
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
(1/7) Installing nghttp2-libs (1.41.0-r0)
(2/7) Installing libcurl (7.69.1-r2)
(3/7) Installing expat (2.2.9-r1)
(4/7) Installing pcre2 (10.35-r0)
(5/7) Installing git (2.26.2-r0)
(6/7) Installing make (4.3-r0)
(7/7) Installing tzdata (2020c-r1)
Executing busybox-1.31.1-r19.trigger
OK: 25 MiB in 22 packages
WARNING: ca-certificates.crt does not contain exactly one certificate or CRL: skipping
INFO[0042] Taking snapshot of full filesystem...
INFO[0045] WORKDIR /go/whoami
INFO[0045] cmd: workdir
INFO[0045] Changed working directory to /go/whoami
INFO[0045] Creating directory /go/whoami
INFO[0045] Taking snapshot of files...
INFO[0045] COPY go.mod .
INFO[0045] Taking snapshot of files...
INFO[0045] COPY go.sum .
INFO[0045] Taking snapshot of files...
INFO[0045] RUN GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download
INFO[0045] cmd: /bin/sh
INFO[0045] args: [-c GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download]
INFO[0045] Running: [/bin/sh -c GO111MODULE=on GOPROXY=https://proxy.golang.org go mod download]
INFO[0045] Taking snapshot of full filesystem...
INFO[0047] COPY . .
INFO[0047] Taking snapshot of files...
INFO[0047] RUN make build
INFO[0047] cmd: /bin/sh
INFO[0047] args: [-c make build]
INFO[0047] Running: [/bin/sh -c make build]
CGO_ENABLED=0 go build -a --trimpath --installsuffix cgo --ldflags="-s" -o whoami
INFO[0058] Taking snapshot of full filesystem...
INFO[0062] Saving file usr/share/zoneinfo for later use
INFO[0062] Saving file etc/ssl/certs/ca-certificates.crt for later use
INFO[0062] Saving file go/whoami/whoami for later use
INFO[0062] Deleting filesystem...
INFO[0063] No base image, nothing to extract
INFO[0063] Executing 0 build triggers
INFO[0063] Unpacking rootfs as cmd COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo requires it.
INFO[0063] COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
INFO[0063] Taking snapshot of files...
INFO[0063] COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
INFO[0063] Taking snapshot of files...
INFO[0063] COPY --from=builder /go/whoami/whoami .
INFO[0063] Taking snapshot of files...
INFO[0063] ENTRYPOINT ["/whoami"]
INFO[0063] EXPOSE 80
INFO[0063] cmd: EXPOSE
INFO[0063] Adding exposed port: 80/tcp

最后正常退出,构建并推送镜像成功。

  • 查看构建镜像是否落盘本地
1
docker images|grep kaniko-demo

执行完命令,没有任何输出,符合预期。构建之后的镜像,直接被推送到了远程 Registry。

  • DockerHub 查看镜像

在 DockerHub 页面可以查看到推送的镜像:

  • 使用镜像,创建容器

执行命令:

1
docker run -d -p 8011:80 shaowenchen/kaniko-demo:v1

验证服务是否正常:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl localhost:8011

Hostname: 6dd22f1e4100
IP: 127.0.0.1
IP: 172.17.0.2
RemoteAddr: 172.17.0.1:40940
GET / HTTP/1.1
Host: localhost:8011
User-Agent: curl/7.29.0
Accept: */*

3.3 在 Kubernetes 上运行 Kaniko

  • 查看 Kubernetes 版本 - v1.17.9

对于不同版本的 Kubernetes,下面有些命令会有所差异,需要自行适配。

1
2
3
4
kubectl version

Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.9", GitCommit:"4fb7ed12476d57b8437ada90b4f93b17ffaeed99", GitTreeState:"clean", BuildDate:"2020-07-15T16:18:16Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.9", GitCommit:"4fb7ed12476d57b8437ada90b4f93b17ffaeed99", GitTreeState:"clean", BuildDate:"2020-07-15T16:10:45Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}
  • 创建命名空间
1
kubectl create ns kaniko-demo
  • 创建镜像推送秘钥
1
2
3
4
5
kubectl -n kaniko-demo create secret docker-registry kaniko-secret \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=YOUR_USERNAME \
  --docker-password=YOUR_PASSWORD \
  --docker-email=mail@chenshaowen.com
  • 创建 kaniko Pod 构建镜像
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cat > kaniko-builder.yaml <<-EOF
apiVersion: v1
kind: Pod
metadata:
  name: kaniko
  namespace: kaniko-demo
spec:
  containers:
  - name: kaniko
    image: gcr.io/kaniko-project/executor:latest
    args:
    - "--dockerfile=Dockerfile"
    - "--context=git://github.com/traefik/whoami"
    - "--destination=shaowenchen/kaniko-demo:v2"
    volumeMounts:
    - name: kaniko-secret
      mountPath: /kaniko/.docker/
  restartPolicy: Never
  volumes:
  - name: kaniko-secret
    secret:
      secretName: kaniko-secret
      items:
          - key: .dockerconfigjson
            path: config.json
EOF

创建 Pod

1
kubectl apply -f kaniko-builder.yaml
  • 查看日志
1
kubectl -n kaniko-demo logs kaniko

日志内容与直接在 Docker 中运行类似,这里就不重复贴出。

  • 查看 DockerHub 页面的镜像

  • 使用构建的镜像创建负载
1
kubectl -n kaniko-demo run kaniko --image=shaowenchen/kaniko-demo:v2
  • 暴露服务并查看服务端口
1
kubectl -n  kaniko-demo expose deploy/kaniko --type=NodePort --port=80 --target-port=80
1
2
3
kubectl -n  kaniko-demo get svc
NAME     TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kaniko   NodePort   10.233.27.225   <none>        80:30772/TCP   29s
  • 验证构建的镜像能正常使用
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl 192.168.13.3:30772

Hostname: kaniko-5ddbf597b6-5h8k8
IP: 127.0.0.1
IP: 10.233.90.187
RemoteAddr: 192.168.13.3:11443
GET / HTTP/1.1
Host: 192.168.13.3:30772
User-Agent: curl/7.29.0
Accept: */*

4. 其他关注的问题

  • 支持 ARM 镜像构建

在最新的版本中,已经可以看到 ARM 的 Kaniko 执行器: https://github.com/GoogleContainerTools/kaniko/releases/tag/v1.3.0

  • 无法给 Git 仓库单独配置秘钥和分支参数

官方提供的一种方式是直接将秘钥和分支参数拼接在 Git 仓库的 URL 中

  • 没有提供构建之前的 prehook 命令

需要在 Dockerfile 中完整描述从源码到镜像的构建过程。最好借助于分阶段构建,改造有些项目中直接 Copy 构建产物的的 Dockerfile 。类似下面的 Dockerfile 不能直接使用:

1
2
3
4
5
6
7
FROM java:openjdk-8-jre-alpine

WORKDIR /home

COPY target/*.jar /home

ENTRYPOINT java -jar *.jar

5. 参考