K8S 制作离线镜像

2020-07-06 container k8s

大部分的镜像制作都是通过 Dockerfile 来实现的,基本都是基于基础镜像制作,这里介绍使用 buildah 来构建基础镜像,可以以此理解其基本原理。

简介

通过 Buildah 从头搭建一个镜像,这里会制作一些常见的镜像,详细可以查看 GitHub 中的介绍。

----- 用来初始化当前的工作路径
container=$(buildah from scratch)
mountpoint=$(buildah mount $container)

----- 可以通过如下方式清理
buildah containers
buildah unmount working-container
buildah rm working-container
----- 最暴力的清理所有
buildah rm --all

----- 增加EntryPoint,其中前者会默认增加 /bin/bash -c 前缀,等价于 /bin/bash -c "/pause"
buildah config --entrypoint /pause $container
buildah config --entrypoint '["/pause"]' $container

在打包前,建议使用 buildah run $container bash 进入到容器中运行所需的程序,否则经常会因为一些异常导致实际容器运行异常。

制作完镜像后可以通过 rsync -ave ssh mysql.tar slave1:/root 命令将其同步到相关服务器。

常用镜像

如下简单列举一些常用的示例。

pause

用来回收子进程,有点类似 Linux 系统中 init 的作用,同时作为 Pod 中 namespace 的占用。源码在 GitHub 中,其中 orphan.c 为测试使用,可以暂时忽略,可以直接编译,然后添加到镜像的根目录下即可。

gcc -Os -Wall -Werror -static -o pause pause.c
strip pause
buildah copy $container pause /     ---> 或者 cp pause $mountpoint/
buildah config --entrypoint '["/pause"]' $container
buildah commit --format docker $container pause
podman save --compress -o pause.tar pause

docker load -i pause.tar
docker tag localhost/pause:latest k8s.gcr.io/pause:3.2
docker rmi localhost/pause

注意,可以先确定报错时使用的 pause 版本号是那个,然后再指定对应 tag 信息,可以从 kubelet 的日志或者通过 kubectl cluster-info dump 命令查看,当前一般就是 3.2 版本。

alpine

如果已经有 rootfs 了,那么可以在执行 mount 之后将其复制到 $mountpoint 目录下即可,例如 alpinelinux 中的。

cp rootfs/* $mountpoint
buildah run $container /bin/sh
buildah commit --format docker $container alpine

podman save --compress -o alpine.tar alpine
docker load -i alpine.tar
docker tag localhost/alpine:latest alpine:latest

CentOS

如果只是单独运行,其实完全可以只添加对应的二进制及其依赖,但考虑到需要登录容器排查问题,所以通常会打包一个包含基础包以及 bash 的镜像。

dnf install --installroot $mountpoint --releasever 1 bash coreutils mysql -y
dnf clean --installroot $mountpoint all

yum install --installroot $mountpoint --release ${distrorelease} bash coreutils \
    --setopt install_weak_deps=false -y
yum clean --installroot $mountpoint all

buildah run $container bash

buildah commit --format docker $container centos

podman images
podman run -it centos bash

这里实际以及安装完成,后面介绍一些其它可选的操作

FILE=runecho.sh
/bin/cat <<EOM >$FILE
#!/usr/bin/env bash
for i in {1..9}; do
    echo "Hello World"
done
EOM
chmod +x $FILE
buildah copy $container $FILE /usr/bin
buildah run $container /usr/bin/runecho.sh
buildah config --entrypoint /usr/bin/runecho.sh $container
buildah config --author "Andy" --created-by "Andy" --label name=${centos} $container

buildah inspect $container
podman run -t centos

docker load -i centos.tar
docker tag localhost/centos:latest centos:latest
docker rmi localhost/centos

Nginx

dnf install --installroot $mountpoint --releasever 1 bash coreutils nginx -y
dnf clean --installroot $mountpoint all
/bin/cat <<EOM >/tmp/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World</title>
  </head>
  <body>
    <p>Hey</p>
  </body>
</html>
EOM
buildah copy $container /tmp/index.html /usr/share/nginx/html/
buildah config --entrypoint '["/usr/sbin/nginx","-g","daemon off;"]' $container
buildah commit --format docker $container nginx
podman save --compress -o nginx.tar nginx

docker load -i nginx.tar
docker tag localhost/nginx:latest nginx:latest
docker rmi localhost/nginx

curl 127.1:80

CoreDNS

CoreDNS 通过 GoLang 编写,部署时实际只使用一个二进制文件即可。

buildah copy $container /etc/ssl/certs /etc/ssl/certs
buildah copy $container coredns /
buildah config --port 53 --port 53/udp $container
buildah config --entrypoint '["/coredns"]' $container
buildah commit --format docker $container coredns
podman save --compress -o coredns.tar coredns

docker load -i coredns.tar
docker tag localhost/coredns:latest coredns/coredns:1.8.3
docker rmi localhost/coredns

详细可以查看 Dockerfile 中的介绍。

MySQL

可以直接参考官方的 Dockerfile 文件,需要将一些相关的脚本文件复制过来,简化后的 Dockerfile 文件如下。

FROM localhost/centos:latest

RUN yum install -y mysql-server && yum clean all
RUN mkdir /docker-entrypoint-initdb.d

COPY prepare-image.sh /
RUN /prepare-image.sh && rm -f /prepare-image.sh

ENV MYSQL_UNIX_PORT /var/lib/mysql/mysql.sock

COPY docker-entrypoint.sh /entrypoint.sh
COPY healthcheck.sh /healthcheck.sh
ENTRYPOINT ["/entrypoint.sh"]
HEALTHCHECK CMD /healthcheck.sh
EXPOSE 3306 33060 33061
CMD ["mysqld"]

dnf install --installroot $mountpoint --releasever 1 bash coreutils mysql-server mysql -y
dnf clean --installroot $mountpoint all
buildah mkdir $container /docker-entrypoint-initdb.d
buildah copy $container prepare-image.sh /
buildah run $container /prepare-image.sh && rm -f /prepare-image.sh
buildah config --env MYSQL_UNIX_PORT=/var/lib/mysql/mysql.sock $container
buildah copy $container docker-entrypoint.sh /entrypoint.sh
buildah copy $container healthcheck.sh /healthcheck.sh
buildah config --entrypoint '["/entrypoint.sh"]' $container
buildah config --healthcheck /healthcheck.sh $container
buildah config --port 3306 --port 33060 --port 33061 $container
buildah config --cmd 'mysqld' $container
buildah commit --format docker $container mysql
podman save --compress -o mysql.tar mysql

docker load -i mysql.tar
docker tag localhost/mysql:latest mysql:latest
docker rmi localhost/mysql

使用时可以通过环境变量进行定制化配置,如下是常见配置:

  • MYSQL_ROOT_PASSWORD 设置ROOT密码。
  • MYSQL_USER 通常为业务用户。
  • MYSQL_PASSWORD 业务用户密码。
  • MYSQL_DATABASE 业务数据库。

而且,允许用户在 /docker-entrypoint-initdb.d 目录下设置一些常见的初始化脚本。

参考