scratch
首先,scratch这个是空的docker镜像,既然是空的,它不支持从docker hub直接下载,(提示报错)。不用手动拉(或创建)该镜像,直接在Dockerfile中用就行。而且,它是docker里面默认的关键字。
它的好处:空镜像scratch,能在符合我们实际业务需求的前提下,确保镜像尺寸尽可能的小。而且,没有预装其他的软件,能使镜像更安全,增加被攻击的难度。
资源
本文参考的资源有:
创建
如果真的想创建这样一个空的镜像。
tar cv --files-from /dev/null | docker import - scratch
不用手动拉(或创建)该镜像,直接在Dockerfile中用就行。
示例
示例1
随便增加几个文件,然后添加到scratch里面。但是,下面的镜像,是不能直接运行的。除非,添加go编译的工具(没有依赖的那种),它能直接跟内核交互。
FROM scratch
ADD . /work
示例2
这个是裸内核上直接运行我们go编译后的文件。其中,go编译文件,使用了两阶段构建。
golang源码 main.go
package main
import (
"fmt"
"time"
)
func main() {
for i := 1; i <= 10000; i++ {
fmt.Printf("hello world %d\n", i)
time.Sleep(time.Duration(2) * time.Second)
}
}
dockerfile
FROM golang:1.16 as build
WORKDIR /work
COPY main.go .
RUN go build main.go
FROM scratch
COPY --from=build /work/main /work/main
CMD ["/work/main"]
构建、运行
# 构建
docker build -t myown:0.2 .
# 运行,每隔1秒输出内容
docker run -it --rm myown:0.2
对镜像进行分析
# 保存自己的镜像
docker save myown:0.2 > myown.tar
# 解压镜像,查看解压出来的文件
tar xvf myown.tar
# 查看解压出来的文件夹
ls
# hash值可能不一样,具体分析
cd 1015307a0efe206b2c7ad45445b189194d54d3113f3300b42221a821a2a83487/
# 解压该层的存储文件
tar xvf layer.tar
ls
# 查看 work 实际上是自己上面自己放进去的位置
cd work/
ls
我们看到,go可以跑在裸内核上,这是因为go自己封装好了运行时。(当然如果引用了依赖c扩展的代码,可能就不行了)。
示例3
从网上直接下载debian的rootfs,然后构建。
下载地址
FROM scratch
ADD rootfs.tar.xz /
# 下面这个可加、可不加
CMD ["bash"]
构建镜像
docker build -t mydebian:0.1 .
运行镜像:
docker run -it --rm mydebian:0.1 bash
# 发现以下命令都是可用的
ls
who
whoami
ps
top
示例4
在上一个示例的基础上,继续完善,比如安装一个nginx服务等。
创建自己的index页面
cat > index.html <<EOL
<h1>Hi,my friends!!!</h1>
EOL
下面重定向nginx的日志到标准的输入、错误,是个亮点。
FROM scratch
# set the environment to honour SAP's proxy servers
#ENV http_proxy http://sap.corp:8080
# give yourself some credit
LABEL maintainer="chuanchao"
# add and unpack an archive that contains a Debian root filesystem
ADD rootfs.tar.xz /
# use the apt-get package manager to install nginx and wget
# 下面的过程可能会很长
RUN apt-get update && \
apt-get -y install nginx wget
#COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /var/www/html/index.html
# link nginx log files to Docker log collection facility
# 两点操作
RUN ln -sf /dev/stdout /var/log/nginx/access.log && \
ln -sf /dev/stderr /var/log/nginx/error.log
# expose port 80 - the standard port for webservers
EXPOSE 80
# and make sure that nginx runs when a container is created
CMD ["nginx", "-g", "daemon off;"]
构建
docker build -t mydebian:0.2 .
运行
docker run --rm -d -p 8030:80 mydebian:0.2
# 浏览器访问服务 ip:8030
# 查看服务的日志 (上面经过重定向输入到日志)
docker logs -f a3c2aea1fcfb14312
上面的例子,能完整的运行。
示例5
直接拷贝一个现有的镜像呢
FROM myown:0.2 as build
FROM scratch
COPY --from=build / /
CMD ["/work/main"]
构建、运行
# 构建
docker build -t myown:0.3 .
# 运行
docker run -it --rm myown:0.3
# 我们发现是可以正常输出的
再用更复杂的镜像呢?
FROM mydebian:0.2 as build
FROM scratch
# 拷贝文件太多,可能需要一定时间
COPY --from=build / /
CMD ["nginx", "-g", "daemon off;"]
构建、运行
docker build -t mydebian:0.3 .
docker run --rm -d -p 8030:80 mydebian:0.3
# 浏览器访问服务 ip:8030
# 查看服务的日志 (上面经过重定向输入到日志)
docker logs -f 47d2e20287d6e14a594c
发现也是可以正常运行的。我猜测,其他的镜像应该也是一样的吧!!!
镜像大小 从239MB减少到232MB(前面只是简单的全部拷贝)
从系统镜像
经过上面的探索,我们初步感受到,可以从系统的镜像iso文件中,提取想用到的镜像。那么,如何构建呢?
centos
查看centos的构建过程:
https://github.com/CentOS/sig-cloud-instance-images/tree/CentOS-7.8.2003-x86_64/docker
如下,即为其构建过程:
FROM scratch
ADD centos-7.8.2003-x86_64-docker.tar.xz /
LABEL \
org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20200504" \
org.opencontainers.image.title="CentOS Base Image" \
org.opencontainers.image.vendor="CentOS" \
org.opencontainers.image.licenses="GPL-2.0-only" \
org.opencontainers.image.created="2020-05-04 00:00:00+01:00"
CMD ["/bin/bash"]
这说明,对于这些基本的centos等直接从scratch镜像构建。所以,我大概明白了,公司的0号镜像是如何来的呢。
修改centos
上面的压缩文件,我们解压后、再重新添加文件后,再重新构建。主要操作如下:
# 解压文件
tar xvf centos-7.8.2003-x86_64-docker.tar.xz
# 重新打包到另外一个目录下,当然我们可以修改它。
mkdir -p ../docker04
tar -zcvf ../docker04/mycentos.tar.gz .
# 进入新的文件夹进行操作
cd docker04/
# Dockerfile
cat > Dockerfile <<<EOL
FROM scratch
ADD mycentos.tar.gz /
CMD ["/bin/bash"]
EOL
# 构建 并运行,发现基本命令都是ok的呢。
# 这说明,如果我们能从操作系统上提炼出我们自己的系统镜像,就ok了
docker build -t mymycentos:0.1 .
docker run --rm -it mymycentos:0.1
其实我在想,既然docker的形式,能运行,感觉把镜像解压后,(增加若干启动有关的东西),便也能运行起来?就算不行,(chroot应该可以吧?)