【基础知识】Docker镜像存储原理及其优化方式

本文旨在通过Dockerfile的指令展开Docker镜像的原理,不再介绍Docker是什么了。

一、核心指令及其增强语法

1. 基础指令

 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
# FROM 每个 Dockerfile 都必须以 FROM 指令开始
FROM ubuntu:20.04
# RUN 执行命令并将结果打包到镜像中,通常用于安装软件或执行某些配置操作
RUN apt-get update && apt-get install -y nginx
# CMD 指定容器启动时默认执行的命令。不同于 RUN,CMD 只在容器启动时执行。
CMD ["nginx", "-g", "daemon off;"]
# ENTRYPOINT 设置容器启动时要执行的主命令。与 CMD 类似,但更适合于设置不可更改的启动命令。
# 一个Dockerfile只能有一个ENTRYPOINT,出现多个时,前面会被最后一个所覆盖
# 通常来说可以和CMD配合使用,如
# ENTRYPOINT ["nginx"]
# CMD ["-g", "daemon off;"]
# 这样启动的时候,可以通过 docker run my_image -g "daemon on;" 这种方式覆盖CMD同时保留默认启动参数的效果
ENTRYPOINT ["nginx", "-g", "daemon off;"]

WORKDIR /app

# COPY 从构建主机将文件或目录复制到镜像中
# ADD 与 COPY 类似,但可以处理本地 tar 文件的自动解压以及 URL 的下载
COPY . /app
ADD https://example.com/app.tar.gz /app

ENV APP_VERSION 1.0
# 声明容器的外部端口,但不自动发布端口
EXPOSE 80
# VOLUME 声明挂载点,将容器的数据目录映射到宿主机目录或其他容器。
# 即使不使用该指令,在docker run启动时,仍然可以使用-v或--mount进行挂载
# docker run -v <宿主机目录>:<容器内目录> <镜像名>
# docker run --mount type=bind,source=<宿主机目录>,target=<容器内目录> <镜像名>
VOLUME ["/data"]

# ONBUILD 用于定义`延迟执行`的构建指令,即当该镜像被用作基础镜像来构建其他镜像时才会执行。一般情况下,它不会在构建当前镜像时触发。
# 举我用到的场景:
# 1. 同步私有仓库管理的config文件,可能有因为不同项目或者语言导致相同的配置数据出现异构
# 2. 安装依赖包搭建编译环境
# 一般来说都是在构建派生镜像时需要拉取最新配置或者依赖包时,可以通过ONBUILD降低派生镜像Dockerfile的复杂度
ONBUILD COPY . /app
ONBUILD RUN cd /app && npm install

上面命令基本足够编写一个复杂的镜像构建脚本,但个别有一些高级选项,可以继续研究一下

2.基础指令上高阶用法

RUN其实有两种缓存layer的方式,分别是

1
2
3
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt

RUN --mount=type=bind,source=/path/to/local/.m2,target=/root/.m2 mvn install

COPYADD都有一个link选项,用于让Docker在将文件或目录从宿主机复制到镜像时,创建硬链接而不是直接复制文件。

在普通Web项目里面很少用到,但在AI训练机器上会很常见,例如这里Depot AI。 因为AI的数据集非常庞大,不可能完全复制到镜像当中,这会导致构建的镜像过大而占用制品库空间,可以通过link的形式将文件链接到镜像的文件系统中。

1
2
3
4
FROM python:3.10

COPY --link --from=depot.ai/runwayml/stable-diffusion-v1-5 /v1-inference.yaml .
COPY --link --from=depot.ai/runwayml/stable-diffusion-v1-5 /v1-5-pruned.ckpt .

二、镜像构建原理,Layers之间的关系

我觉得需要搞明白一件事情就是,Docker不是VM,任意基础镜像都不存在安装一个完整的操作系统。

docker-image.png

Read more...

【CKA专题】梳理RBAC权限构成,并创建一个用户及其权限

为一个开发人员配置客户端证书

首先,为用户生成私钥和证书签名请求(CSR),然后使用Kubernetes集群的CA来签署证书

使用 OpenSSL 生成私钥和证书签名请求(CSR):

1
2
3
4
5
# 生成用户的私钥
openssl genrsa -out user.key 2048

# 生成CSR
openssl req -new -key user.key -out user.csr -subj "/CN=username/O=groupname"

在这里:

  • /CN=usernameusername表示用户的名字
  • /O=groupnamegroupname表示用户所在的组,可以帮助后续RBAC授权(例如管理员、开发者等不同组)

使用 Kubernetes 集群的 CA 签署 CSR,生成用户证书:

1
openssl x509 -req -in user.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out user.crt -days 365
  • -CA /etc/kubernetes/pki/ca.crt 和 -CAkey /etc/kubernetes/pki/ca.key:指向 Kubernetes 集群的CA证书和CA密钥,用于签署用户的CSR
  • -out user.crt:生成的用户证书

配置 kubeconfig 文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
kubectl config set-cluster kubernetes-cluster \
  --certificate-authority=ca.crt \
  --server=https://<API_SERVER_IP>:<PORT> \
  --kubeconfig=$KUBECONFIG_FILE
## 添加用户的证书和私钥
kubectl config set-credentials username --client-certificate=user.crt --client-key=user.key --kubeconfig=$KUBECONFIG_FILE
## 为用户设置一个使用上下文,以便访问集群
kubectl config set-context username-context --cluster=kubernetes-cluster --namespace=default --user=username --kubeconfig=$KUBECONFIG_FILE
## 切换到新创建的上下文
kubectl config use-context username-context --kubeconfig=$KUBECONFIG_FILE

将文件给到开发同学即可

Read more...

【基础知识】Linux的xargs命令

昨天在给服务器做年终“大扫除”整理时,发现有个目录下因为文件过多而删除失败,最终使用xargs才搞定,于是顺便来记录下。

在执行某些命令时,当 Linux 某个目录下文件过多就会因为“参数列表过长”而报错无法执行。比如,我要清空/var/spool/clientmqueue/下的庞大数量的临时文件, 如果直接执行rm -f *,有时就会会出现“参数列表过长”的错误提示,因为 linux 下一般的命令的参数的总长度不能超过 4096 个字节。

这时,xargs就应该上场了了,由于服务器数量很多,我直接在每台服务器上执行如下命令,即可清理此文件夹内的所有文件:

1
2
#代码中的$8,不通系统发行版本可能有所区别,具体使用 ls -l 查看文件名在那一列即可
cd /var/spool/clientmqueue/  && ls -l /var/spool/clientmqueue/ | awk {'print $8'} | xargs rm -f
Read more...