Docker 的出现为开发人员和运维人员带来了极大的便利,在使用Docker容器时,有没有想过docker镜像是怎么来的呢,虽然现在可以从网上的镜像仓库下载镜像,但是第三方提供的镜像有时候并不符合我们的要求,我们有必要创建自己的基础镜像,然后在这个基础镜像上面,去构建各种应用镜像。本文将介绍创建Docker基础镜像的两种方法,分别是:1、通过tar打包现有的操作系统,然后导入Docker镜像仓库;2、使用mkimage-yum.sh脚本制作;

基础环境:

         1、两种方式我都是在同一台虚拟机上操作的完成的,首先我们要准备好基础的操作系统,此次我通过虚拟机安装的rhel7.4的操作系统,安装方式是最小化安装,因为我们需要将建出来的基础镜像尽可能的小。

docker构建 windows docker构建基础镜像_Docker


2、安装好docker。

方式一:本地直接打包导入方式

1、安装好最小化系统之后,使用tar进行打包,排除一些不必要的目录。

tar --numeric-owner --exclude=/proc --exclude=/sys --exclude=/mnt --exclude=/tmp --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 /tmp/rhel7.4-Base.tar.gz /

2、导入到docker镜像

[root@localhost /]# cat /tmp/rhel7.4-Base.tar.gz| docker import - rhel7.4-tar
sha256:33b316e0e89c08462ef93affa55ed1768045bc73e33d0c6ded6cd837f0da1af8
[root@localhost /]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7.4-tar         latest              33b316e0e89c        7 seconds ago       978MB

3、运行容器

[root@localhost /]#  docker run -it rhel7.4-tar  /bin/bash
[root@0a56c30bbf0a /]# df -h
文件系统               容量  已用  可用 已用% 挂载点
overlay                 39G  2.8G   36G    8% /
tmpfs                   64M     0   64M    0% /dev
tmpfs                  997M     0  997M    0% /sys/fs/cgroup
shm                     64M     0   64M    0% /dev/shm
/dev/mapper/rhel-root   39G  2.8G   36G    8% /etc/hosts
tmpfs                  997M     0  997M    0% /proc/acpi
tmpfs                  997M     0  997M    0% /proc/scsi
tmpfs                  997M     0  997M    0% /sys/firmware
[root@0a56c30bbf0a /]# more /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.4 (Maipo)

方式二:mkimage-yum.sh脚本方式

1、脚本地址:https://raw.githubusercontent.com/docker/docker/master/contrib/mkimage-yum.sh或者https://github.com/moby/moby/blob/master/contrib/mkimage-yum.sh
2、脚本内容

#!/usr/bin/env bash
#
# Create a base CentOS Docker image.
#
# This script is useful on systems with yum installed (e.g., building
# a CentOS image on CentOS).  See contrib/mkimage-rinse.sh for a way
# to build CentOS images on other systems.

set -e

usage() {
    cat <<EOOPTS
$(basename $0) [OPTIONS] <name>
OPTIONS:
  -p "<packages>"  The list of packages to install in the container.
                   The default is blank. Can use multiple times.
  -g "<groups>"    The groups of packages to install in the container.
                   The default is "Core". Can use multiple times.
  -y <yumconf>     The path to the yum config to install packages from. The
                   default is /etc/yum.conf for Centos/RHEL and /etc/dnf/dnf.conf for Fedora
  -t <tag>         Specify Tag information.
                   default is reffered at /etc/{redhat,system}-release
EOOPTS
    exit 1
}

# option defaults
yum_config=/etc/yum.conf
if [ -f /etc/dnf/dnf.conf ] && command -v dnf &> /dev/null; then
	yum_config=/etc/dnf/dnf.conf
	alias yum=dnf
fi
# for names with spaces, use double quotes (") as install_groups=('Core' '"Compute Node"')
install_groups=()
install_packages=()
version=
while getopts ":y:p:g:t:h" opt; do
    case $opt in
        y)
            yum_config=$OPTARG
            ;;
        h)
            usage
            ;;
        p)
            install_packages+=("$OPTARG")
            ;;
        g)
            install_groups+=("$OPTARG")
            ;;
        t)
            version="$OPTARG"
            ;;
        \?)
            echo "Invalid option: -$OPTARG"
            usage
            ;;
    esac
done
shift $((OPTIND - 1))
name=$1

if [[ -z $name ]]; then
    usage
fi

# default to Core group if not specified otherwise
if [ ${#install_groups[*]} -eq 0 ]; then
   install_groups=('Core')
fi

target=$(mktemp -d --tmpdir $(basename $0).XXXXXX)

set -x

mkdir -m 755 "$target"/dev
mknod -m 600 "$target"/dev/console c 5 1
mknod -m 600 "$target"/dev/initctl p
mknod -m 666 "$target"/dev/full c 1 7
mknod -m 666 "$target"/dev/null c 1 3
mknod -m 666 "$target"/dev/ptmx c 5 2
mknod -m 666 "$target"/dev/random c 1 8
mknod -m 666 "$target"/dev/tty c 5 0
mknod -m 666 "$target"/dev/tty0 c 4 0
mknod -m 666 "$target"/dev/urandom c 1 9
mknod -m 666 "$target"/dev/zero c 1 5

# amazon linux yum will fail without vars set
if [ -d /etc/yum/vars ]; then
	mkdir -p -m 755 "$target"/etc/yum
	cp -a /etc/yum/vars "$target"/etc/yum/
fi

if [[ -n "$install_groups" ]];
then
    yum -c "$yum_config" --installroot="$target" --releasever=/ --setopt=tsflags=nodocs \
        --setopt=group_package_types=mandatory -y groupinstall "${install_groups[@]}"
fi

if [[ -n "$install_packages" ]];
then
    yum -c "$yum_config" --installroot="$target" --releasever=/ --setopt=tsflags=nodocs \
        --setopt=group_package_types=mandatory -y install "${install_packages[@]}"
fi

yum -c "$yum_config" --installroot="$target" -y clean all

cat > "$target"/etc/sysconfig/network <<EOF
NETWORKING=yes
HOSTNAME=localhost.localdomain
EOF

# effectively: febootstrap-minimize --keep-zoneinfo --keep-rpmdb --keep-services "$target".
#  locales
rm -rf "$target"/usr/{{lib,share}/locale,{lib,lib64}/gconv,bin/localedef,sbin/build-locale-archive}
#  docs and man pages
rm -rf "$target"/usr/share/{man,doc,info,gnome/help}
#  cracklib
rm -rf "$target"/usr/share/cracklib
#  i18n
rm -rf "$target"/usr/share/i18n
#  yum cache
rm -rf "$target"/var/cache/yum
mkdir -p --mode=0755 "$target"/var/cache/yum
#  sln
rm -rf "$target"/sbin/sln
#  ldconfig
rm -rf "$target"/etc/ld.so.cache "$target"/var/cache/ldconfig
mkdir -p --mode=0755 "$target"/var/cache/ldconfig

if [ -z "$version" ]; then
    for file in "$target"/etc/{redhat,system}-release
    do
        if [ -r "$file" ]; then
            version="$(sed 's/^[^0-9\]*\([0-9.]\+\).*$/\1/' "$file")"
            break
        fi
    done
fi

if [ -z "$version" ]; then
    echo >&2 "warning: cannot autodetect OS version, using '$name' as tag"
    version=$name
fi

tar --numeric-owner -c -C "$target" . | docker import - $name:$version

docker run -i -t --rm $name:$version /bin/bash -c 'echo success'

rm -rf "$target"

3、运行脚本创建

[root@localhost /]# chmod 777 mkimage-yum.sh
[root@localhost /]#./mkimage-yum.sh -y /etc/yum.conf rhel7.4-mk

4、等待执行完成,查看是否创建成功。

[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
rhel7.4-mk          7.7.1908            2e4f95289f64        18 minutes ago      281MB
rhel7.4-tar         latest              33b316e0e89c        41 minutes ago      978MB
[root@localhost /]#  docker run -it rhel7.4-mk:7.7.1908  /bin/bash
[root@c9b2fa5d5e50 /]# df -h
Filesystem             Size  Used Avail Use% Mounted on
overlay                 39G  3.1G   36G   8% /
tmpfs                   64M     0   64M   0% /dev
tmpfs                  997M     0  997M   0% /sys/fs/cgroup
shm                     64M     0   64M   0% /dev/shm
/dev/mapper/rhel-root   39G  3.1G   36G   8% /etc/hosts
tmpfs                  997M     0  997M   0% /proc/acpi
tmpfs                  997M     0  997M   0% /proc/scsi
tmpfs                  997M     0  997M   0% /sys/firmware
[root@c9b2fa5d5e50 /]# more /etc/redhat-release 
CentOS Linux release 7.7.1908 (Core)

总结:

1、两种方式都能实现,通过比对可以发现通过tar打包创建的基础镜像的体积大约是通过mkimage-yum.sh脚本创建的基础镜像的3倍左右,
2、两个镜像的版本不一致,tar打包的方式生成的镜像版本和虚拟机一致rhel7.4,而脚本方式的镜像版本是centos7.7,猜测是以yum源的版本生成的。
3、两种方式各有特点,tar方式可以自定义安装软件和版本等,体积大;而脚本方式只能安装官方yum源里面支持的包,不能自定义,但是体积小。