如何创建CentOS系统的Docker基础镜像

在使用Docker容器时,我们经常需要基于一些基础镜像(Base Image)来构建符合自己要求的镜像。通常,我们会使用DockerHub或其他镜像市场提供的基础镜像。虽然这样很方便,但是我们并不知道第三方提供的基础镜像的实现细节和安全性,若在生产环境贸然使用这些基础镜像,则可能会带来技术隐患。因此,有必要创建自己的基础镜像!本文将详述创建CentOS系统(6.9版本和7.4版本)的Docker基础镜像的两种方法,分别是:

  • 通过tar打包已有的CentOS系统,然后导入Docker镜像仓库;
  • 通过mkimage-yum.sh脚本,使用yum下载和安装必要的软件包,然后导入Docker镜像仓库。

本文会使用两台虚拟机,分别安装CentOS 6.9系统和CentOS 7.4系统。

一、环境描述

1. 虚拟机-1

  • CPU:双核
  • 内存:4 GB
  • 硬盘:120 GB
  • 操作系统:CentOS 6.9 x86_64
  • 安装方式:Minimal
  • IP地址:172.17.243.169

2. 虚拟机-2

  • CPU:双核
  • 内存:4 GB
  • 硬盘:120 GB
  • 操作系统:CentOS 7.4.1708 x86_64
  • 安装方式:Minimal
  • IP地址:172.17.243.168

二、通过tar打包构建基础镜像

Step-1 卸载不必要的软件包

为了缩小文件系统的体积,需要删除一些不必要的软件包。在Shell中执行以下命令:

CentOS 6.9系统(虚拟机-1):

  1. yum remove -y iwl* ql* xorg* ipw* *firmware* --exclude=kernel-firmware

CentOS 7.4.1708系统(虚拟机-2):

  1. yum remove -y iwl* *firmware* --exclude=kernel-firmware

Step-2 清除yum缓存

清除yum缓存,进一步缩小文件系统的体积。在Shell中执行以下命令:

CentOS 6.9系统(虚拟机-1):

  1. yum clean all

CentOS 7.4.1708系统(虚拟机-2):

  1. yum clean all
  2. rm -rf /var/cache/yum

Step-3 打包文件系统

将文件系统打包,排除所有运行时才创建的目录,以及不必要的目录。在Shell中执行以下命令:

CentOS 6.9系统(虚拟机-1):

  1. tar --numeric-owner --exclude=/proc --exclude=/sys --exclude=/mnt --exclude=/var/cache --exclude=/usr/share/{foomatic,backgrounds,perl5,fonts,cups,qt4,groff,kde4,icons,pixmaps,emacs,gnome-background-properties,sounds,gnome,games,desktop-directories} --exclude=/var/log -zcvf /mnt/CentOS-6.9-BaseImage.tar.gz /

CentOS 7.4.1708系统(虚拟机-2):

  1. tar --numeric-owner --exclude=/proc --exclude=/sys --exclude=/mnt --exclude=/var/cache --exclude=/usr/share/{foomatic,backgrounds,perl5,fonts,cups,qt4,groff,kde4,icons,pixmaps,emacs,gnome-background-properties,sounds,gnome,games,desktop-directories} --exclude=/var/log -zcvf /mnt/CentOS-7.4-BaseImage.tar.gz /

Step-4 安装和启动Docker

安装CentOS的EPEL源和REMI源,然后安装Docker软件包,最后启动Docker服务。在Shell中运行一下命令:

CentOS 6.9系统(虚拟机-1):

  1. # 安装EPEL源和REMI源
  2. rpm -Uvh https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
  3. rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-6.rpm
  4. # 安装Docker软件包
  5. yum install -y docker-io
  6. # 启动Docker服务
  7. service docker start

CentOS 7.4.1708系统(虚拟机-2):

  1. # 安装EPEL源和REMI源
  2. rpm -Uvh https://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-10.noarch.rpm
  3. rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm
  4. # 安装Docker软件包
  5. yum install -y docker-io
  6. # 启动Docker服务
  7. systemctl start docker.service

Step-5 导入镜像仓库

将打包的文件系统,导入Docker的本地镜像仓库。在Shell中运行以下命令:

CentOS 6.9系统(虚拟机-1):

  1. cat /mnt/CentOS-6.9-BaseImage.tar.gz | docker import - centos-tar:6.9

CentOS 7.4.1708系统(虚拟机-2):

  1. cat /mnt/CentOS-7.4-BaseImage.tar.gz | docker import - centos-tar:7.4.1708

Step-6 验证

检查Docker的本地镜像仓库,若如下图所示,则表明镜像创建成功:

CentOS 6.9系统(虚拟机-1):
通过tar打包创建的CentOS 6.9基础镜像

CentOS 7.4.1708系统(虚拟机-2):
通过tar打包创建的CentOS 7.4基础镜像

运行一个示例容器,在控制台中输出提示信息,如下图所示:

CentOS 6.9系统(虚拟机-1):
通过tar打包创建的CentOS 6.9基础镜像的运行示例

CentOS 7.4.1708系统(虚拟机-2):
通过tar打包创建的CentOS 7.4基础镜像的运行示例

三、通过mkimage-yum.sh脚本构建基础镜像

Step-1 安装第三方源

安装CentOS的EPEL源和REMI源。在Shell中运行以下命令:

CentOS 6.9系统(虚拟机-1):

  1. rpm -Uvh https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
  2. rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-6.rpm

CentOS 7.4.1708系统(虚拟机-2):

  1. rpm -Uvh https://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-10.noarch.rpm
  2. rpm -Uvh https://rpms.remirepo.net/enterprise/remi-release-7.rpm

Step-2 安装和启动Docker

安装Docker软件包,然后启动Docker服务。在Shell中运行以下命令:

CentOS 6.9系统(虚拟机-1):

  1. yum install -y docker-io
  2. service docker start

CentOS 7.4.1708系统(虚拟机-2):

  1. yum install -y docker-io
  2. systemctl start docker.service

Step-3 创建脚本文件

新建mkimage-yum.sh脚本,这个文件就是Docker官方的创建镜像的脚本文件,URL为:

  1. https://github.com/moby/moby/blob/master/contrib/mkimage-yum.sh

在Shell中运行以下命令:

  1. vi mkimage-yum.sh

CentOS 6.9和CentOS 7.4的脚本内容相同,如下所示:

  1. #!/usr/bin/env bash
  2. #
  3. # Create a base CentOS Docker image.
  4. #
  5. # This script is useful on systems with yum installed (e.g., building
  6. # a CentOS image on CentOS). See contrib/mkimage-rinse.sh for a way
  7. # to build CentOS images on other systems.
  8. set -e
  9. usage() {
  10. cat <<EOOPTS
  11. $(basename $0) [OPTIONS] <name>
  12. OPTIONS:
  13. -p "<packages>" The list of packages to install in the container.
  14. The default is blank.
  15. -g "<groups>" The groups of packages to install in the container.
  16. The default is "Core".
  17. -y <yumconf> The path to the yum config to install packages from. The
  18. default is /etc/yum.conf for Centos/RHEL and /etc/dnf/dnf.conf for Fedora
  19. EOOPTS
  20. exit 1
  21. }
  22. # option defaults
  23. yum_config=/etc/yum.conf
  24. if [ -f /etc/dnf/dnf.conf ] && command -v dnf &> /dev/null; then
  25. yum_config=/etc/dnf/dnf.conf
  26. alias yum=dnf
  27. fi
  28. install_groups="Core"
  29. while getopts ":y:p:g:h" opt; do
  30. case $opt in
  31. y)
  32. yum_config=$OPTARG
  33. ;;
  34. h)
  35. usage
  36. ;;
  37. p)
  38. install_packages="$OPTARG"
  39. ;;
  40. g)
  41. install_groups="$OPTARG"
  42. ;;
  43. \?)
  44. echo "Invalid option: -$OPTARG"
  45. usage
  46. ;;
  47. esac
  48. done
  49. shift $((OPTIND - 1))
  50. name=$1
  51. if [[ -z $name ]]; then
  52. usage
  53. fi
  54. target=$(mktemp -d --tmpdir $(basename $0).XXXXXX)
  55. set -x
  56. mkdir -m 755 "$target"/dev
  57. mknod -m 600 "$target"/dev/console c 5 1
  58. mknod -m 600 "$target"/dev/initctl p
  59. mknod -m 666 "$target"/dev/full c 1 7
  60. mknod -m 666 "$target"/dev/null c 1 3
  61. mknod -m 666 "$target"/dev/ptmx c 5 2
  62. mknod -m 666 "$target"/dev/random c 1 8
  63. mknod -m 666 "$target"/dev/tty c 5 0
  64. mknod -m 666 "$target"/dev/tty0 c 4 0
  65. mknod -m 666 "$target"/dev/urandom c 1 9
  66. mknod -m 666 "$target"/dev/zero c 1 5
  67. # amazon linux yum will fail without vars set
  68. if [ -d /etc/yum/vars ]; then
  69. mkdir -p -m 755 "$target"/etc/yum
  70. cp -a /etc/yum/vars "$target"/etc/yum/
  71. fi
  72. if [[ -n "$install_groups" ]];
  73. then
  74. yum -c "$yum_config" --installroot="$target" --releasever=/ --setopt=tsflags=nodocs \
  75. --setopt=group_package_types=mandatory -y groupinstall "$install_groups"
  76. fi
  77. if [[ -n "$install_packages" ]];
  78. then
  79. yum -c "$yum_config" --installroot="$target" --releasever=/ --setopt=tsflags=nodocs \
  80. --setopt=group_package_types=mandatory -y install "$install_packages"
  81. fi
  82. yum -c "$yum_config" --installroot="$target" -y clean all
  83. cat > "$target"/etc/sysconfig/network <<EOF
  84. NETWORKING=yes
  85. HOSTNAME=localhost.localdomain
  86. EOF
  87. # effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target".
  88. # locales
  89. rm -rf "$target"/usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
  90. # docs and man pages
  91. rm -rf "$target"/usr/share/{man,doc,info,gnome/help}
  92. # cracklib
  93. rm -rf "$target"/usr/share/cracklib
  94. # i18n
  95. rm -rf "$target"/usr/share/i18n
  96. # yum cache
  97. rm -rf "$target"/var/cache/yum
  98. mkdir -p --mode=0755 "$target"/var/cache/yum
  99. # sln
  100. rm -rf "$target"/sbin/sln
  101. # ldconfig
  102. rm -rf "$target"/etc/ld.so.cache "$target"/var/cache/ldconfig
  103. mkdir -p --mode=0755 "$target"/var/cache/ldconfig
  104. version=
  105. for file in "$target"/etc/{redhat,system}-release
  106. do
  107. if [ -r "$file" ]; then
  108. version="$(sed 's/^[^0-9\]*\([0-9.]\+\).*$/\1/' "$file")"
  109. break
  110. fi
  111. done
  112. if [ -z "$version" ]; then
  113. echo >&2 "warning: cannot autodetect OS version, using '$name' as tag"
  114. version=$name
  115. fi
  116. tar --numeric-owner -c -C "$target" . | docker import - $name:$version
  117. docker run -i -t --rm $name:$version /bin/bash -c 'echo success'
  118. rm -rf "$target"

Step-4 导入镜像仓库

运行mkimage-yum.sh脚本,创建CentOS的基础镜像,CentOS 6.9和CentOS 7.4的命令相同:

  1. chmod 755 mkimage-yum.sh
  2. ./mkimage-yum.sh centos-mkimage

Step-5 验证

检查Docker的本地镜像仓库,若如下图所示,则表明镜像创建成功:

CentOS 6.9系统(虚拟机-1):
通过mkimage-yum.sh脚本创建的CentOS 6.9基础镜像

CentOS 7.4.1708系统(虚拟机-2):
通过mkimage-yum.sh脚本创建的CentOS 7.4基础镜像

运行一个示例容器,在控制台中输出提示信息,如下图所示:

CentOS 6.9系统(虚拟机-1):
通过mkimage-yum.sh脚本创建的CentOS 6.9基础镜像的示例

CentOS 7.4.1708系统(虚拟机-2):
通过mkimage-yum.sh脚本创建的CentOS 7.4基础镜像的示例

四、两种方法对比

在虚拟机-1中查看两种方法创建的CentOS 6.9的基础镜像,如下图所示:
两种创建CentOS 6.9基础镜像的方法对比

在虚拟机-2中查看两种方法创建的CentOS 7.4的基础镜像,如下图所示:
两种创建CentOS 7.4基础镜像的方法对比

由上述两图可知,通过tar打包创建的基础镜像的体积大约是通过mkimage-yum.sh脚本创建的基础镜像的3倍左右。这是由于前者是基于最小化安装的CentOS系统而创建的,而后者是从CentOS官方源安装必要的软件包而创建的,前者比后者多安装了很多软件包,包括邮件工具、设备驱动程序,等等。这两种方法各有特点:

  • 通过tar打包创建:基础镜像体积较大,但可以按照需求自由定制,适用于各种版本的CentOS系统,灵活度较高。
  • 通过mkimage-yum.sh脚本创建:基础镜像体积较小,但只能安装官方源支持的软件包,并且只适用于最新版本的CentOS系统。

用户可以根据自己的需求特点,选择本文介绍的一种方法来创建属于自己的CentOS基础镜像!