手动制作

Docker镜像有没有内核?

从镜像大小上面来说,一个比较小的镜像只有十几MB,而内核文件需要一百多兆,因此镜像里面是没有内核的,镜像在被启动为容器后将直接使用宿主机的内核,而镜像本身则只提供相应的rootfs,即系统正常运行所必须的用户空间的文件系统,比如/dev/ , /proc,/bin,/etc等目录,所以容器当中基本是没有/boot目录的,而/boot当中保存的就是与内核相关的文件和目录。

为什么没有内核?
由于容器启动和运行过程中是直接使用了宿主机的内核,所以没有直接调用过物理硬件,所以也不会涉及到硬件驱动,因此也用不上内核和驱动,另外有内核的那是虚拟机。

手动制作yum版nginx镜像

Docker制作类似于虚拟机的模板制作,即按照公司的实际业务务求将需要安装的软件、相关配置等基础环境配置完成,然后将虚拟机再提交为模板,最后再批量从模板批量创建新的虚拟机,这样可以极大的简化业务中相同环境的虚拟机运行环境的部署工作,Docker的镜像制作分为手动制作和自动制作(基于DockerFile),企业通常都是基于Dockerfile制作镜像,其中手动制作镜像步骤具体如下:

下载镜像并初始化系统

基于某个基础镜像之上重新制作,因此需要先有一个基础镜像,本次使用官方提供的centos镜像为基础:

1
2
3
4
5
6
7
8
9
10
[root@docker01 ~]$ docker pull centos
[root@docker01 ~]$ docker run -it centos bash
[root@d08b9898e6b3 /]# cd /etc/yum.repos.d/
[root@d08b9898e6b3 yum.repos.d]# rm -rf ./*
[root@d08b9898e6b3 yum.repos.d]# curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo
[root@d08b9898e6b3 yum.repos.d]# yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm
[root@d08b9898e6b3 yum.repos.d]# sed -i 's|^#baseurl=https://download.fedoraproject.org/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
[root@d08b9898e6b3 yum.repos.d]# sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
[root@d08b9898e6b3 yum.repos.d]# dnf makecache
[root@d08b9898e6b3 yum.repos.d]# dnf install -y vim wget pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop

yum安装并配置nginx

1
2
3
[root@d08b9898e6b3 yum.repos.d]# dnf install nginx -y #安装nginx
[root@d08b9898e6b3 html]# cat /usr/share/nginx/html/index.html
I love Linux!

关闭nginx后台运行

1
2
3
4
5
6
[root@d08b9898e6b3 /]# vim /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
daemon off;

提交为镜像

不要退出容器,另起一个宿主机终端操作

1
2
3
4
5
6
7
8
[root@docker01 ~]$ docker commit --help
Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
Create a new image from a container's changes
Options:
-a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list Apply Dockerfile instruction to the created image
-m, --message string Commit message
-p, --pause Pause container during commit (default true)
1
[root@docker01 ~]$ docker commit -a "kinmfer kinmfer@foxmail.com" -c "EXPOSE 80" -m "Nginx yum v1" d08b9898e centos-nginx-v1:1.16.1

image-20200725155740149

验证镜像

1
[root@docker01 ~]$ docker run -it -p 8001:80 centos-nginx-v1:1.16.1  nginx

如果在配置nginx时未加入daemon off,则应以如下命令启动

1
[root@docker01 ~]$ docker run -it -p 8001:80 centos-nginx-v1:1.16.1  nginx "-g daemon off;"

image-20200725160234056

手动制作编译版本nginx镜像

过程为在centos基础镜像之上手动编译安装nginx,然后再提交为镜像

下载镜像并初始化系统

1
2
3
4
5
6
7
8
9
10
[root@docker01 ~]$ docker pull centos
[root@docker01 ~]$ docker run -it centos bash
[root@84ac00d2d9d2 /]# cd /etc/yum.repos.d/
[root@84ac00d2d9d2 yum.repos.d]# rm -rf ./*
[root@84ac00d2d9d2 yum.repos.d]# curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo
[root@84ac00d2d9d2 yum.repos.d]# yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm
[root@84ac00d2d9d2 yum.repos.d]# sed -i 's|^#baseurl=https://download.fedoraproject.org/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
[root@84ac00d2d9d2 yum.repos.d]# sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
[root@84ac00d2d9d2 yum.repos.d]# dnf makecache
[root@84ac00d2d9d2 yum.repos.d]# dnf install -y vim wget make tree gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop

编译安装nginx

1
2
3
4
5
6
7
8
9
[root@84ac00d2d9d2 src]# wget http://nginx.org/download/nginx-1.18.0.tar.gz
[root@84ac00d2d9d2 src]# tar -xf nginx-1.18.0.tar.gz
[root@84ac00d2d9d2 src]# cd nginx-1.18.0
[root@84ac00d2d9d2 nginx-1.18.0]# ./configure --prefix=/apps/nginx
[root@84ac00d2d9d2 nginx-1.18.0]# make
[root@84ac00d2d9d2 nginx-1.18.0]# make install
[root@84ac00d2d9d2 nginx-1.18.0]# cd /apps/nginx
[root@84ac00d2d9d2 nginx]# vim html/index.html
I love Docker!

这里将nginx命令设置了软链接,这样就可以直接以nginx命令启动容器,否则在启动容器时需要写成/app/nginx/sbin/nginx,有类似情况需要注意

提交为镜像

1
[root@docker01 ~]$ docker commit -a "kinmfer kinmfer@foxmail.com" -m "Nginx make v1" 84ac00d2d9d2 centos-nginx:v1

image-20200725163054478

验证镜像

由于没有在nginx配置文件里加入daemon off,所以启动容器的时候要加入参数nginx "-g daemon off;"

1
[root@docker01 ~]$ docker run -it -p 8002:80 centos-nginx:v1 nginx "-g daemon off;"

image-20200725163803500

Docker不建议再通过这种方式构建镜像;具体原因如下

  • 手工创建,容易出错,效率低并且可重复性弱。
  • 无法对镜像进行审计,存在安全隐患。

Dockfile制作

基础介绍

DockerFile可以说是一种可以被Docker程序解释的脚本,DockerFile是由一条条的命令组成的,每条命令对应Linux下面的一条命令,Docker程序将这些DockerFile指令再翻译成真正的Linux命令,其有自己的书写方式和支持的命令,Docker程序读取DockerFile并根据指令生成Docker镜像,相比手动制作镜像的方式,DockerFile更能直观的展示镜像是怎么产生的,有了写好的各种各样DockerFile文件,当后期某个镜像有额外的需求时,只要在之前的DockerFile添加或者修改相应的操作即可重新生成新的Docker镜像,避免了重复手动制作镜像的麻烦,具体如下:

https://docs.docker.com/engine/reference/builder/

注意:Dockerfile里涉及到的Linux命令需要FROM的基础镜像中有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM			# 基础镜像,一切从这里开始构建
LABEL # kv对
RUN # 镜像构建的时候需要运行的命令
ADD # 添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 暴露端口配置,跟 -p 是一个道理
ONBUILD # 当构建一个被继承DockerFile 这个时候就会运行ONBUILD的指令。触发指令
COPY # 类似ADD,将我们文件拷贝到镜像中
ENV # 构建的时候设置环境变量,跟 -e 是一个意思
CMD # 指定这个容器启动时要执行的命令,只有最后一个命令会生效,可被替代
ENTRYPOINT # 指定这个容器启动的时候要执行的命令,可以追加命令
USER # 指定

# CMD 和 ENTRYPOINT 的区别说明:(后面也会介绍)
# 若CMD 和 ENTRYPOINT 后跟的都是 ls -a 这个命令,当docker run 一个容器时,添加了 -l 选项,则CMD里的ls -a 命令就会被替换成-l;而ENTRYPOINT中的 ls -a会追加-l变成 ls -a -l

FROM

  • FROM指令是最重的一个且必须为Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境
  • 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会在docker主机上查找指定的镜像文件,在其不存在时,则会从Docker Hub Registry上拉取所需的镜像文件。如果找不到指定的镜像文件,docker build会返回一个错误信息
  • Syntax
    FROM<repository>[:<tag>]
    FROM<resository>@<digest>
    • reposotiry :指定作为base inage的名称;
    • <tag>: base inage的标签,为可选项,省咯时默认为latest;

MAINTAINER(现以 LABEL +kv对来实现)

  • 用于让Dockerfile制作者提供本人的详细信息

  • Dockerfile并不限制MAINTAINER指令可在出现的位置,但推荐将其放置于FROM指令之后

  • Syntax
    MAINTAINER <authtor's detail>
    MAINTAINER "kinmfer<kinmfer@foxmail.com>"

  • <author’s detail>可是任何文本信息,但约定俗成地使用作者名称及邮件地址

  • 现被LABEL maintainer="kinimfer <kinmfer@foxmail.com>"代替


LABEL

  • 用来在镜像中添加元数据,一个镜像可以有多个LABEL,可以在一行定义

  • 一个LABEL标签是一个kv对

  • 要在标签值中包含空格,请像在命令行分析中那样使用引号和反斜杠。

  • Syntax:

    1
    LABEL<key>=<value> <key>=<value> <key>=<value>...

COPY

  • 用于从Docker主机复制文件至创建的新映像文件
  • Syntax
    COPY <src> ...<dest>
    COPY ["<src>",..."<dest>"]
    • <src>:要复制的源文件或目录,支持使用通配符
    • <dest>:目标路径,即正在创建的image的文件系统路径;建议为<dest>使用绝对路径,否则,COPY指定则以WORKDIR为其起始路径;
    • 注意:在路径中有空白字符时,通常使用第二种格式
  • 文件复制准则
    • <src>必须是build上下文中的路径,不能是其父目录中的文件
    • 如果<src>是目录,则其内部文件或子目录会被递归复制,但<src>目录自身不会被复制
    • 如果指定了多个<src>,或在<src>中使用了通配符,则<dest>必须是一个目录,且必须以/结尾
    • 如果<dest>事先不存在,它将会被自动创建,这包括其父目录路径

ADD

  • ADD指令类似于COPY指令,ADD支持使用TAR文件和URL路径
  • Syntax
    ADD<src> ..<dest>
    ADD["<src>",... "<dest>"]
  • 操作准则
    • 同COPY指令
    • 如果<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载并直接被创建为<dest>;如果<dest>以/结尾,则文件名URL指定的文件将被直接下载并保存为<dest>/<filename>
    • 如果<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开;
    • 如果<rc>有多个,或其间接或直接使用了通配符,则<dest>必须是一个以/结尾的目录路径;如果<dest>不以/结尾,则其被视作一个普通文件,<src>的内容将被直接写入到<dest>;

WORKDIR

  • 用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD指定设定工作目录
  • Syntax
    • WORKDIR<dirpath>
      • 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个WORKDIR指令指定的路径
      • 另外,WORKDIR也可调用由ENV指定定义的变量
    • 例如
      • WORKDIR /var/log
      • WORKD1R $STATEPATH

VOLUMN

  • 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷
  • Syntax
    • VOLUME <mountpoint≥
      VOLUME["<mountpoint>"]
  • 如果挂载点目录路径下此前在文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

EXPOSE

  • 用于为容器打开指定要监听的端口以实现与外部通信,只有在运行容器时加-P选项才会真正暴露端口
  • Syntax
    EXPOSE<port>[<protocol>][[]...]
    • <protocol>用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议
  • EXPOSE指令可一次指定多个端口,例如
    • EXPOSE 11211/udp 11211/tcp

ENV

  • 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)调用
  • 调用格式为$variable_name或${variable_name}
  • Syntax
    ENV <key> <value>
    ENV <key>=<value> ...
  • 第一种格式中,<key>之后的所有内容均会被视作其<value>的组成部分,因此,一次只能设置一个变量;
  • 第二种格式可用一次设置多个变量,每个变量为一个”<key>=<value>”的键值对,如果<value>中包含空格,可以以反斜线(N)进行转义,也可通过对<value>加引号进行标识;另外,反斜线也可用于续行;
  • 定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能

RUN

  • 用于指定docker build过程中运行的程序,其可以是任何命令
  • Syntax
    RUN <command>
    RUN ["<executable>", "<param1>", "<param2>"]注意:要使用双引号
  • 第一种格式中,<command>通常是一个shell命令,且以”/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>命令停止容器时,此进程接收不到SIGTERM信号;
  • 第二种语法格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以”/bin/sh-c”来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
    RUN["/bin/bash", "-c","<executable>", "<param1>"]

CMD

  • 类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
    • RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新镜像文件启动一个容器时
    • CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖
    • 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效
  • Syntax
    • CMD <command>
      CMD["<executable>","<param1>","<param2>"]
      CMD["<param1>","<param2>"]
    • 前两种语法格式的意义同RUN
    • 第三种则用于为ENTRYPOINT指今提供默认参数

ENTRYPOINT

  • 类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序
  • 与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序
    • 不过,docker run命令的–entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序
  • Syntax
    ENTRYPOINT<command>
    ENTRYPOINT["<executable>", "<param1>", "<param2>"]
  • docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用
  • Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效

USER

  • 用于指定运行image时的或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID
  • 默认情况下,container的运行身份为root用户
  • Syntax
    USER <UID>|<UserName>
  • 需要注意的是,<UID>可以为任意数字,但实践中其必须为/etc/passwd中某用户的有效UID,否则,docker run命令将运行失败

ONBUILD

  • 用于在Dockerfile中定义一个触发器
  • Dockerfile用于build映像文件,此映像文件亦可作为base image被另一个Dockerfile用作FROM指令的参数,并以之构建新的映像文件
  • 在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会”触发”创建其base image的Dockerfile文件中的ONBUILD指令定义的触发器
  • Syntax
    ONBUILD <INSTRUCTION>
  • 尽管任何指令都可注册成为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令
  • 使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如ruby:2.0-onbuild
  • 在ONBUILD指令中使用ADD或COPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败

DockerFile制作编译版nginx1.18.0镜像

下载镜像并初始化系统

1
2
3
4
[root@docker01 ~]$ docker pull centos
[root@docker01 ~]$ docker run -it centos bash
[root@docker01 opt]$ cd /opt
[root@docker01 opt]$ mkdir -p dockfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat} }#目录结构按照业务类型或系统类型等方式划分,方便后期镜像比较多的时候进行分类。

进入到指定目录

1
2
3
[root@docker01 dockfile]$ cd web/nginx/
[root@docker01 nginx]$ pwd
/opt/dockfile/web/nginx

编写Dockfile文件

1
[root@docker01 nginx]$ vim ./Dockerfile

生成的镜像的时候会在执行命令的当前目录查找Dockerfile文件,所以名称不可写错,而且D必须大写

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
# My Dockerfile
# "#"为注释,等于shell脚本的中#
# 除了注释行之外的第一行,必须是From xxx (xxx是基础镜像)
FROM centos#第一行先定义基础镜像,后面的本地有效的镜像名,如果本地没有会从远程仓库下载,第一行很重要
# 镜像维护者的信息
LABEL maintainer="kinmfer <kinmfer@foxmail.com>"
# 或者这样写
# MAINTAINER kinmfer kinmfer@foxmail.com
########################## 其他可选参数
###############################################
#USER #指定该容器运行时的用户名和UID,后续的RUN命令也会使用这面指定的用户执行
#WORKDIR /a
#WORKDIR b #指定工作目录,最终为/a/b
#VOLUME["/dir_1", "/dir_2" ..]设置容器挂载主机目录。
#ENV name kinmfer#设置容器变量,常用于想容器内传递用户密码等
###############################################
###############################################
#执行的命令,将编译安装nginx的步骤执行一遍。
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo
RUN yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm
RUN sed -i 's|^#baseurl=https://download.fedoraproject.org/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
RUN sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
RUN dnf makecache
RUN dnf install -y vim wget make tree unzip gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop
ADD nginx-1.18.0.tar.gz /usr/local/src # .tar.gz的文件会直接解压,但是.zip的文件不会,因此需要提前安装unzip。nginx-1.18.0.tar.gz文件在Dockfile同级目录
RUN cd /usr/local/src/nginx-1.18.0 && ./configure --prefix=/apps/nginx && make && make install && rm -rf nginx-1.18.0.tar.gz nginx-1.18.0
ADD static.zip /apps/nginx/html # 模拟导包格式为.zip static.zip文件在Dockfile同级目录
RUN cd /apps/nginx/html && unzip static.zip && rm -rf static.zip
EXPOSE 80 443 #向外开放的端口,多个端口用空格做间隔,启动容器时候-p需要使用此端向外映射.如:-p8081:80,则80就是这里的80

CMD ["/apps/nginx/sbin/nginx","-g","daemon off;"] # 容器启动时运行的命令,每个Dockfile只能有一条,如果有多条则只有最后一条被执行。

如果在从该镜像启动容器的时候也指定了命令,那么该指定的命令会覆盖Dockfile构建的镜像里的CMD命令,即指定的命令优先级更高

准备源码包和配置文件

image-20200726101527438

执行镜像构建

1
[root@docker01 nginx]$ docker build -t nginx-1.18.0:v1 .

image-20200726093027167

构建完成

image-20200726093536435

启动容器

image-20200726093622987

访问web界面

image-20200726093819788

自定义Tomcat镜像

基于官方提供的centos、debain、ubuntu、alpine等基础镜像构建JDK(Java环境),然后再基于自定义的JDK镜像构建出业务需要的tomcat镜像。

构建JDK镜像

先基于官方提供的基础镜像,制作出安装了常用命令的自定义基础镜像,然后在基础镜像的基础之上,再制作JDK镜像、Tomcat镜像等。

自定义CentOS基础镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@docker01 ~]$ docker pull centos
[root@docker01 ~]$ docker run -it centos bash
[root@docker01 opt]$ cd /opt
[root@docker01 opt]$ mkdir -p dockfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,alpine,debian} }
[root@docker01 centos]$ vim Dockerfile
#CentOS 8.2 Base Image
FROM centos
LABEL maintainer="kinmfer <kinmfer@foxmail.com>"
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo
RUN yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm
RUN sed -i 's|^#baseurl=https://download.fedoraproject.org/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel*
RUN sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel*
RUN dnf makecache
RUN dnf install -y vim wget make tree unzip gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop diffutils systemd-devel
RUN groupadd www -g 2020 && useradd www -u 2020 -g www && groupadd nginx -g 2021 && useradd nginx -u 2021 -g nginx
[root@docker01 centos]$ vim build-command.sh
#!/bin/bash
docker build -t centos-base:v1 .
[root@docker01 centos]$ bash build-command.sh #通过脚本进行镜像构建

执行构建JDK镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
# CentOS 8.2 jdk-8u261
FROM centos-base:v1
LABEL maintainer="kinmfer <kinmfer@foxmail.com>"
ADD jdk-8u261-linux-x64.tar.gz /usr/local/src/
RUN ln -sv /usr/local/src/jdk1.8.0_261 /usr/local/jdk
ADD profile /etc/profile

ENV JAVA_HOME /usr/local/jdk
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/
ENV PATH $PATH:$JAVA_HOME/bin

RUN rm -rf /etc/localtime && ln -snf /usr/share/zoninfo/Asia/Shanghai /etc/localtime

上传JDK压缩包和profile文件

image-20200726135450463

执行构建自定义JDK基础镜像

1
2
3
[root@docker01 jdk-8u261]$ vim docker-command.sh
#!/bin/bash
docker build -t centos-jdk:8u261 .

验证

image-20200726135837505

构建Tomcat9镜像

基于自定义的JDK基础镜像,构建出通用的自定义Tomcat基础镜像,此镜像后期会被多个业务的多个服务共同引用(相同的JDK版本和Tomcat版本)。

编写Dockfile

1
2
3
4
5
# CentOS 8.2 tomcat9.0.37
FROM centos-jdk:8u261
LABEL maintainer="kinmfer kinmfer@foxmail.com"
ADD apache-tomcat-9.0.37.tar.gz /apps
RUN ln -sv /apps/apache-tomcat-9.0.37 /apps/tomcat

上传Tomcat9源码包

image-20200726140540560

执行构建自定义JDK基础镜像

1
2
3
[root@docker01 jdk-8u261]$ vim docker-command.sh
#!/bin/bash
docker build -t centos-tomcat:9.0.37 .

验证

image-20200726140705488

image-20200726140818418

构建业务镜像1

创建app1和app2两个目录,表示基于tomcat自定义基础镜像构建出不同业务的tomcat app镜像。

准备Dockerfile1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#Tomcat Web Image

FROM centos-tomcat:9.0.37

LABEL mantainer="kinmfer <kinmfer@foxmail.com>"

ADD server.xml /apps/tomcat/conf/server.xml

ADD app1.tar.gz /data/tomcat/webapps

ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh

RUN chown www.www /apps -R

EXPOSE 8080 8005 8009

CMD ["/apps/tomcat/bin/run_tomcat.sh"]

准备自定义app1界面

1
2
3
[root@docker01 tomcat-app1]$ mkdir app1
[root@docker01 tomcat-app1]$ echo "I Love Docker!" > app1/index.html
[root@docker01 tomcat-app1]$ tar zxf app1.tar.gz app1/

准备容器启动执行脚本

1
2
3
4
5
6
7
8
[root@docker01 tomcat-app1]$ cat run_tomcat.sh
#!/bin/bash
# 模拟操作
echo "1.1.1.1 test1.kinmfer.com" >> /etc/hosts
echo "namesercer 223.5.5.5" >> /etc/resolv.conf

su - www -c "/apps/tomcat/bin/catalina.sh start"
tail -f /etc/hosts

执行构建

1
2
3
[root@docker01 tomcat-app1]$ cat build_command.sh
#!/bin/bash
docker build -t centos-tomcat-app1:v1 .

image-20200726161342634

验证

image-20200726161412272

image-20200726161514735

构建业务镜像2

有了之前的app1,则app2可以很快的部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@docker01 tomcat]$ cp -rf tomcat-app1/ tomcat-app2
[root@docker01 tomcat]$ cd tomcat-app2/
[root@docker01 tomcat-app2]$ echo "I Love Linux and Docker!" > app1/index.html && mv app1 app2

[root@docker01 tomcat-app2]$ rm -f app1.tar.gz && tar zcf app2.tar.gz app2/
#Tomcat Web Image
FROM centos-tomcat:9.0.37
LABEL mantainer="kinmfer <kinmfer@foxmail.com>"
ADD server.xml /apps/tomcat/conf/server.xml
ADD app2.tar.gz /data/tomcat/webapps
ADD run_tomcat.sh /apps/tomcat/bin/run_tomcat.sh
RUN chown www.www /apps -R
EXPOSE 8080 8005 8009
CMD ["/apps/tomcat/bin/run_tomcat.sh"]

[root@docker01 tomcat-app2]$ vim build_command.sh
#!/bin/bash
docker build -t centos-tomcat-app2:v1 .
[root@docker01 tomcat-app2]$ bash build_command.sh

image-20200726162157369

接下来将app1和app2同时开启验证

image-20200726162429019

基于官方alpine基础镜像制作自定义镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM alpine
LABEL maintainer="kinmfer <kinmfer@foxmail.com>"
COPY repositories /etc/apk/repositories # 换阿里源
RUN apk update && apk addiotopgcc libgcc libc-dev libcurl libc-utils pcre-dev zlib-dev libnfs make pcre pcre2 zip unzip net-tools pstree wget libevent libevent-dev iproute2
ADD nginx-1.18.0.tar.gz /opt/
RUN cd /opt/nginx-1.18.0 && ./configure --prefix=/apps/nginx && make && make
install && ln -sv/apps/nginx/sbin/nginx /usr/bin/
RUN addgroup -g 2020 -S nginx && adduser -s /sbin/nologin -S -D -u 2020 -G nginx nginx
COPY nginx.conf /apps/nginx/conf/nginx.conf
ADD static.tar.gz /data/nginx/html
RUN chown nginx.nginx /data/nginx/ /apps/nginx/ -R
EXPOSE 80 443
CMD ["nginx"]

image-20200727080954752

image-20200727081209741

基于官方Ubuntu基础镜像制作自定义镜像

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
# Docker image for nginx
#
#
FROM ubuntu:18.04

LABEL maintainer="kinmfer <kinmfer@foxmail.com>"

ENV password 123456

ADD sources.list /etc/apt

RUN apt update && apt install -y iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev tcpdump gcc openssh-server tree iotop unzip zip make

ADD nginx-1.18.0.tar.gz /usr/local/src

RUN cd /usr/local/src/nginx-1.18.0 && ./configure --prefix=/apps/nginx && make && make install && ln -sv /apps/nginx/sbin/nginx /usr/bin/nginx && rm -rf nginx-1.18.0.tar.gz nginx-1.18.0

ADD static.zip /apps/nginx/html

RUN cd /apps/nginx/html && unzip static.zip && rm -rf static.zip

RUN groupadd -g 2020 nginx && useradd -g nginx -s /sbin/nologin -u 2020 nginx

RUN chown nginx.nginx /apps/nginx -R

EXPOSE 80 443

CMD ["nginx"]

image-20200727091014983

image-20200727091129662

构建HAProxy镜像

构建出haproxy镜像,将haproxy通过容器的方式运行。

准备Dockfile

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM centos-base:v1

LABEL maintainer="kinmfer <kinmfer@foxmail.com>"
ADD haproxy-2.2.1.tar.gz /usr/local/src
RUN cd /usr/local/src/haproxy-2.2.1 && make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy && make install PREFIX=/usr/local/haproxy

ADD haproxy.cfg /etc/haproxy

ADD run_haproxy.sh/usr/bin

EXPOSE 80 9999

CMD["/usr/bin/run_haproxy.sh"]

准备HAProxy源码和配置文件

image-20200727104843557

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
38
39
[root@docker01 haproxy-centos]$ cat haproxy.cfg
global
chroot /usr/local/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
nbproc 1
pidfile /usr/local/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info

defaults
option http-keep-alive
option forwardfor
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms

listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:123456

listen web_port
bind 0.0.0.0:80
mode http
log global
balance roundrobin
server web1 192.168.242.100:8080 check inter 3000 fall 2 rise 5
server web2 192.168.242.101:8080 check inter 3000 fall 2 rise 5

[root@docker01 haproxy-centos]$ cat run_haproxy.sh
#!/bin/bash
/usr/local/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts

启动容器

192.168.242.100(HAProxy+Tomcat)

image-20200727133618308

192.168.242.101(Tomcat)

image-20200727133718338

验证

image-20200727133743739

会在两个页面之间切换

image-20200727133923184


image-20200727133904354

本地镜像上传到官方docker仓库

将自制的镜像上传至docker仓库;https://hub.docker.com/,实现镜像跨主机备份。

注册账户并配置相关信息

在虚拟机上用自己的账号登陆

1
[root@docker01 ~]$ docker login docker.io

image-20200727134949834

设置tag并上传

image-20200727153025431

本地镜像上传到阿里云

将镜像推送到Registry

将本地镜像上传至阿里云,实现镜像备份与统一分发的功能。https://cr.console.aliyun.com

注册账户、创建namespace、创建仓库、修改镜像tag及上传镜像

image-20200727162135690

image-20200727160445640

image-20200727162037308

验证

image-20200727162354708