Docker镜像生产构建

我们已经了解了Docker的基本概念和管理,下面就开始着手创建自己的第一个Docker镜像,这里我们选用最早pull下来的centos作为基础镜像,然后在上面部署Nginx来做案例讲解。

手动构建镜像

手动构建镜像,简单的说就是我们基于一个基础镜像启动一个容器,然后对这个容器进行更改,更改完毕后,进行提交。

启动容器

运行一个CentOS容器,命名为mynginx

[root@linux-node1 ~]# docker pull centos
[root@linux-node1 ~]# docker run --name mynginx -it centos

在容器里面安装Nginx

[root@2e110e00eef4 /]# rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
[root@2e110e00eef4 /]# yum install -y nginx

想要Docker容器保持活跃的状态,需要其中运行的进程不能中断,默认情况下,Nginx会以守护进程的方式启动,这会导致容器只是短暂运行,在守护进程被fork启动后,发起守护进程的原始进程就会退出,这时容器就会停止运行了。所以我们需要将Nginx放在前端运行。

[root@2e110e00eef4 /]# vi /etc/nginx/nginx.conf
#在配置文件最上面增加下面配置
daemon off;
[root@2e110e00eef4 /]# exit

提交镜像

获取容器ID

[root@linux-node1 ~]# docker ps -a | grep mynginx
2e110e00eef4 centos "/bin/bash" 8 minutes ago Exited (0) 2 minutes ago mynginx

提交修改后的容器为镜像

[root@linux-node1 ~]# docker commit -m "My Nginx" 2e110e00eef4 test/mynginx:v1
sha256:cfd25da2c9c5dd2bcce9e5d2ef4e316b46b5f03617176b97b60a34f2958a6d70
  • -m:指定提交的说明信息,类似SVN和Git。
  • 之后是用来创建镜像的容器的 ID;
  • 最后指定目标镜像的仓库名和标签信息。

查看镜像

[root@linux-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/mynginx v1 cfd25da2c9c5 49 seconds ago 373MB
nginx latest f09fe80eb0e7 2 weeks ago 109MB
centos latest 1e1148e4cc2c 2 months ago 202MB

从我们创建的镜像运行一个容器

[root@linux-node1 ~]# docker run -d -p 91:80 test/mynginx:v1 nginx

现在你的手动构建的第一个镜像就完成了。你可以用同样的方式安装任意你需要的软件到镜像里面,然后使用镜像来启动一个容器,只要记住容器启动必须要有一个不会退出的进程在执行即可。

Dockerfile构建

Dockerfile是为快速构建docker image而设计的,当你使用docker build命令的时候,docker 会读取当前目录下的命名为Dockerfile(首字母大写)的纯文本文件并执行里面的指令构建出一个docker image。这比SaltStack的配置管理要简单的多,不过还是要掌握一些简单的指令。

Dockerfile 由一行行命令语句组成,并且支持以#开头的注释行。指令是不区分大小写的,但是通常我们都大写。

下面我们通过构建一个Nginx的镜像来学习Dockerfile的编写。

Nginx Dockerfile实战

注意:第一个指令必须是FROM。

[root@linux-node1 ~]# mkdir -p /opt/dockerfile/mynginx
[root@linux-node1 ~]# cd /opt/dockerfile/mynginx/
[root@test-node1 nginx]# vim Dockerfile
# This docker file uses the centos image
# VERSION 1
# Author: Jason Zhao
# Base image
FROM centos
# Maintainer
MAINTAINER shundong.zhao zhaoshundong@gmail.com
#Commands to update the image
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
RUN yum install -y nginx --enablerepo=epel
ADD index.html /usr/share/nginx/html/index.html
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx"]

为了大家更容易学习,我这里总结一个命令的介绍:

一般的,我们将Dockerfile 分为四部分:

  • 基础镜像信息

  • 维护者信息

  • 镜像操作指令

  • 容器启动时执行指令

常用指令的介绍

构建Dockerfile

注意:ADD index.html就是放一个文件进去,这个文件需要大家自己准备一下。例如:

[root@linux-node1 mynginx]# echo "nginx in docker test" > index.html

使用dokcer build命令构建镜像,最后的.表示当前路径

[root@linux-node1 mynginx]# docker build -t mynginx:v2 .

构建完毕之后,我们就可以Run起来。

[root@linux-node1 ~]# docker run -d -p 92:80 mynginx:v2 nginx

测试访问

[root@linux-node1 mynginx]# curl http://192.168.56.11:92

nginx in docker test

现在你应该发现编写Dockerfile有多么的简单了吧,不过我们还是要系统的再来学习一遍。

Dockerfile命令详解

下面我们来分别介绍下上面使用到的命令:

FROM

格式:FROM 或FROM :

解释:FROM是Dockerfile里的第一条指令(必须是),后面跟有效的镜像名(如果该镜像你的本地仓库没有则会从远程仓库Pull取)。然后后面的其它指令FROM的镜像中执行。

MAINTAINER

格式:MAINTAINER

解释:指定维护者信息。

RUN

格式:RUN 或 RUN ["executable", "param1", "param2"]。

解释:运行命令,命令较长使可以使用来换行。推荐使用上面数组的格式

CMD

格式:

CMD ["executable","param1","param2"] 使用 exec 执行,推荐方式;

CMD command param1 param2 在 /bin/sh 中执行,提供给需要交互的应用;

CMD ["param1","param2"] 提供给ENTRYPOINT的默认参数;

解释:

CMD指定容器启动是执行的命令,每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行。如果你在启动容器的时候也指定的命令,那么会覆盖Dockerfile构建的镜像里面的CMD命令。

ENTRYPOINT

格式:

ENTRYPOINT ["executable", "param1", "param2"]

ENTRYPOINT command param1 param2(shell中执行)。

解释:和CMD类似都是配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。

每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。ENTRYPOINT没有CMD的可替换特性,也就是你启动容器的时候增加运行的命令不会覆盖ENTRYPOINT指定的命令。

所以生产实践中我们可以同时使用ENTRYPOINT和CMD,例如:

ENTRYPOINT ["/usr/bin/rethinkdb"]

CMD ["--help"]

USER

格式:USER daemon

解释:指定运行容器时的用户名和UID,后续的RUN指令也会使用这里指定的用户。

EXPOSE

格式:EXPOSE [...]

解释:设置Docker容器内部暴露的端口号,如果需要外部访问,还需要启动容器时增加-p或者-P参数进行分配。

ENV

格式:ENV

ENV = ...

解释:设置环境变量,可以在RUN之前使用,然后RUN命令时调用,容器启动时这些环境变量都会被指定

ADD

格式:

ADD ...

ADD ["",... ""]

解释:将指定的复制到容器文件系统中的

所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0
如果文件是可识别的压缩格式,则docker会帮忙解压缩

VOLUME

格式:VOLUME ["/data"]

解释:可以将本地文件夹或者其他container的文件夹挂载到container中。

WORKDIR

格式:WORKDIR /path/to/workdir

解释:切换目录,为后续的 RUN、CMD、ENTRYPOINT 指令配置工作目录。

可以多次切换(相当于cd命令),

也可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如

WORKDIR /a

WORKDIR b

WORKDIR c

RUN pwd

则最终路径为 /a/b/c。

ONBUILD

ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行

ARG

格式:ARG [=]

解释:ARG指定了一个变量在docker build的时候使用,可以使用--build-arg

=来指定参数的值,不过如果构建的时候不指定就会报错。

Docker镜像生产规划实践

现在我们学会了如何使用Dockerfile来构建镜像,没错,真正生产环境我们也是大规模的使用Dockerfile。那么我们应该如何入手呢?

首先我们需要参考一些别人编写的Dockerfile,学习一些规范和技巧,可以来这里找找答案:https://github.com/dockerfile

可以参考网友编写的Dockerfile的技巧和方法,那么真正的生产环境,肯定要根据自己公司或者团队的技术栈来构建不同的Docker镜像,根据Docker镜像的分层观念,我们可以在这个基础上对我们的镜像进行分层。

  • 系统层

  • 运行环境层

  • 应用服务层

案例如下:

[root@linux-node1 ~]# mkdir /opt/dockerfile
[root@linux-node1 ~]# cd /opt/dockerfile/
[root@linux-node1 dockerfile]# mkdir system runtime app
[root@linux-node1 dockerfile]# tree
.
├── app
├── runtime
└── system

基础系统镜像

CentOS系统镜像

默认的官方CentOS镜像有很多常用的命令并不提供,可以根据企业需求进行定制。需要注意的是使用yum安装完毕后,记得执行yum clean all。

因为yum会把下载的软件包和header存储在cache中,而不会自动删除。如果我们觉得它们占用了磁盘空间,可以使用yum clean all指令进行清除,可以减少镜像的大小。

[root@linux-node1 ~]# cd /opt/dockerfile/system/
[root@linux-node1 system]# mkdir centos

1.编写Dockerfile

[root@linux-node1 system]# vim centos/Dockerfile
# Docker for CentOS
#Base image
**FROM** centos
#Who
**MAINTAINER** Jason.Zhao xxx@gmail.com
#Base pkg
**RUN** rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
**RUN** yum install -y wget mysql-devel supervisor git redis tree net-tools sudo
psmisc && yum clean all

2.构建镜像

[root@linux-node1 system]# docker build -t unixhot/centos ./centos/

3.查看镜像

[root@linux-node1 system]# docker images | grep unixhot

unixhot/centos latest 4edcb790dacf 24 seconds ago 303 MB

4.使用镜像创建容器

[root@linux-node1 system]# docker run --name mycentos -it unixhot/centos
/bin/bash
[root@b137b1cdd3ac /]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.0 11776 1872 ? Ss 03:56 0:00 /bin/bash
root 15 0.0 0.0 47424 1668 ? R+ 03:56 0:00 ps aux

CentOS系统镜像包含SSH

在很多时候如果你需要在CentOS里面启动sshd服务,那么就需要安装openssh-server并且重新生成SSH的主机密钥。同时如果,你需要给镜像设置一个密码,可以使用chpasswd非交互的方式来进行。

[root@linux-node1 ~]# cd /opt/dockerfile/system/
[root@linux-node1 system]# mkdir centos-ssh

1.编写Dockerfile

[root@linux-node1 system]# vim centos-ssh/Dockerfile
# Docker for CentOS
#Base image
FROM centos
#Who
MAINTAINER Jason.Zhao xxx@gmail.com
#EPEL
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
#Base pkg
RUN yum install -y openssh-clients openssl-devel openssh-server wget mysql-devel
supervisor git redis tree net-tools sudo psmisc && yum clean all
# For SSHD
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key
# Set root password
RUN echo "root:unixhot.com" | chpasswd

2.构建镜像

[root@linux-node1 system]# docker build -t unixhot/centos-ssh:v1 ./centos-ssh/
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM centos
---> 980e0e4c79ec
Step 2 : MAINTAINER Jason.Zhao xxx@gmail.com
---> **Using cache**
---> d08da8648d91
Step 3 : RUN rpm -ivh
http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
---> **Using cache**
---> ad9a05bcfb78
…(省略后面输出)

这里有一个小技巧,为了加快构建的速度,注意到上面前三步的输出Using cache,因为Docker镜像的分层原理,已经构建过的layer不会重复构建。

3.查看镜像

[root@linux-node1 system]# docker images | grep unixhot
unixhot/centos-ssh v1 ff1ab7d7e7f4 19 seconds ago 304 MB
unixhot/centos latest 4edcb790dacf 2 hours ago 303 MB

4.使用镜像创建容器

[root@linux-node1 system]# docker run -d --name centos-ssh-demo -p 8022:22
unixhot/centos-ssh:v1 /usr/sbin/sshd -D
5f5bbe98a17c620f91a7d3e68a605a4bcbd48621f32aaa095245e59a8691e229

[root@linux-node1 system]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5f5bbe98a17c unixhot/centos-ssh:v1 "/usr/sbin/sshd -D" 5 seconds ago Up 2
seconds 0.0.0.0:8022->22/tcp centos-ssh-demo

5.使用ssh连接容器

[root@linux-node1 ~]# ssh -p 8022 root@192.168.56.11
root@192.168.56.11's password:
[root@5f5bbe98a17c ~]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 82560 3600 ? Ss 05:46 0:00 /usr/sbin/sshd -D
root 7 0.0 0.0 11636 1116 ? Ss 05:47 0:00 /bin/bash
root 13 0.0 0.0 11636 1116 ? Ss 05:48 0:00 /bin/bash
root 63 0.7 0.0 139272 5424 ? Ss 05:51 0:00 sshd: root@pts/0
root 65 0.5 0.0 13376 1988 pts/0 Ss 05:51 0:00 -bash
root 78 0.0 0.0 49024 1808 pts/0 R+ 05:51 0:00 ps aux

Good Job,你现在可以通过ssh连接到自己创建的Docker容器上了。但是有没有发现一个问题,Docker只允许在前台运行一个进程,那已经运行了sshd。那么如何运行别的进程呢。显然我们做一个能ssh的镜像,目的就是为了在上面运行各种服务。怎么办呢?有很多解决方案。例如你编写一个脚本start.sh。可以在里面写多个服务的启动命令,只要start.sh不执行完毕,即可。当然真正生产推荐的是使用Supervisor。

使用Supervisor管理进程

Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动、重启、关闭进程(不仅仅是 Python 进程)。除了对单个进程的控制,还可以同时启动、关闭多个进程。

Supervisor 可以运行在 Linux、Mac OS X 上。如前所述,supervisor 是 Python 编写的,所以安装起来也很方便,可以直接用 pip :

pip install supervisor

现在让我们重新创建一个新的不启动ssh的容器,来实验下supervisor的安装和相关配置。以便于,我们编写Dockerfile。

1.启动测试supervisor的docker容器

[root@linux-node1 system]# docker run --rm -it unixhot/centos-ssh:v1 /bin/bash
[root@98aced104917 /]# ls -l /etc/supervisord*
-rw-r--r-- 1 root root 7953 Aug 20 2015 /etc/supervisord.conf
/etc/supervisord.d:
total 0

注意,在上一小节的镜像构建中,我们已经使用yum安装了supervisord。supervisor的配置文件为/etc/supervisord.conf。

2.Supervisor配置

Supervisor 相当强大,提供了很丰富的功能,不过我们可能只需要用到其中一小部分。安装完成之后,可以编写配置文件,来满足自己的需求。为了方便,我们把配置分成两部分:supervisord(supervisor 是一个 C/S 模型的程序,这是 server 端,对应的有 client 端:supervisorctl)和应用程序(即我们要管理的程序)。

[root@98aced104917 /]# vi /etc/supervisord.conf

#下面并没有列出完整的supervisord.conf的配置,默认注释掉的内容,请自行查看。

**[unix_http_server]**

# file=/var/run/supervisor/supervisor.sock #UNIX socket 文件,supervisorctl
会使用

**[supervisord]**
logfile=/var/log/supervisor/supervisord.log #主要日志文件,默认位置是
$CWD/supervisord.log
logfile_maxbytes=50MB #日志文件大小,超出会 rotate,默认 50MB
logfile_backups=10 #日志文件保留备份数量默认 10
loglevel=info #日志级别,默认 info,其它: debug,warn,trace
pidfile=/var/run/supervisord.pid #pid文件位置
**nodaemon=true #注意需要修改的为此处,将supervisor放在前台运行。**
minfds=1024 #可以打开的文件描述符的最小值,默认 1024
minprocs=200 #可以打开的进程数的最小值,默认 200
**[supervisorctl]**

#通过 UNIX socket 连接 supervisord,路径与 unix_http_server 部分的 file 一致

serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL for a
unix socket

**[include]**

#包含supervisord.d目录下*.ini文件,也就是说,我们可以将需要启动应用程序的配置放在这个目录下,这就是运维标准化。

files = supervisord.d/*.ini

3. program 配置

supervisor主配置文件的变更只需要修改nodaemon=true,可以看到关于程序的配置在主配置文件里面都是注释掉的:

;[program:theprogramname]
;command=/bin/cat ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1 ; number of processes copies to start (def 1)
;directory=/tmp ; directory to cwd to before exec (def no cwd)
;umask=022 ; umask for process (default None)
;priority=999 ; the relative start priority (default 999)
;autostart=true ; start at supervisord start (default: true)
;autorestart=true ; retstart at unexpected quit (default: true)

(省略部分输出)

我们现在要做的事情,就是编写一个sshd的程序管理配置,放置到/etc/supervisord.d目录下,注意文件后缀是.ini,你可以复制上面注释掉的内容进行修改:

[root@98aced104917 /]# vi /etc/supervisord.d/sshd.ini
[program:sshd]
command=/usr/sbin/sshd -D
process_name=%(program_name)s
autostart=true
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10

4.启动supervisord

[root@98aced104917 ~]# /usr/bin/supervisord -c /etc/supervisord.conf
[root@98aced104917 ~]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 31/sshd
tcp6 0 0 :::22 :::* LISTEN 31/sshd

可以看到sshd已经启动了。是由supervisor进行启动的。

5. 使用 supervisorctl

Supervisorctl 是 supervisord 的一个命令行客户端工具,可以用来管理supervisord启动的进程。

[root@98aced104917 ~]# supervisorctl status
sshd RUNNING pid 31, uptime 0:02:35

停止与启动sshd

[root@98aced104917 ~]# supervisorctl stop sshd
sshd: stopped

[root@98aced104917 ~]# supervisorctl status
sshd STOPPED Oct 14 06:45 AM

[root@98aced104917 ~]# supervisorctl start sshd
sshd: started

[root@98aced104917 ~]# supervisorctl status
sshd RUNNING pid 42, uptime 0:00:03

6..将supervisord.conf配置文件scp到宿主机目录下,和Dockerfile同目录

[root@98aced104917 /]# scp /etc/supervisord.conf
192.168.56.11:/opt/dockerfile/system/centos-ssh/

[root@98aced104917 ~]# scp /etc/supervisord.d/sshd.ini
192.168.56.11:/opt/dockerfile/system/centos-ssh/

好的,可以退出容器,这个容器的生命周期结束。

标准化CentOS系统镜像

现在我们来构建一个全新的包含ssh的centos系统镜像。同时如果你不需要ssh。你依然可以使用supervisor连进行进程管理。

[root@linux-node1 ~]# cd /opt/dockerfile/system/centos-ssh/
[root@linux-node1 centos-ssh]# ls -l
total 16
-rw-r--r-- 1 root root 554 Oct 14 01:40 Dockerfile
-rw-r--r-- 1 root root 142 Oct 14 02:53 sshd.ini
-rw-r--r-- 1 root root 7953 Oct 14 02:30 supervisord.conf

1.重新编写Dockerfile

[root@linux-node1 centos-ssh]# vim Dockerfile
# Docker for CentOS
#Base image
FROM centos
#Who
MAINTAINER Jason.Zhao xxx@gmail.com
#EPEL
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
#Base pkg
RUN yum install -y openssh-clients openssl-devel openssh-server wget mysql-devel
supervisor git redis tree net-tools sudo psmisc && yum clean all
# For SSHD
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key
# Set root password
RUN echo "root:unixhot.com" | chpasswd
#Supervisord config
ADD supervisord.conf /etc/supervisord.conf
ADD sshd.ini /etc/supervisord.d/sshd.ini
# Outside Port
EXPOSE 22
#supervisord start
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

2.构建镜像

[root@linux-node1 centos-ssh]# docker build -t unixhot/centos-ssh:latest .

3.查看镜像

[root@linux-node1 centos-ssh]# docker images | grep unixhot
unixhot/centos-ssh latest 0d4b39f9100e 31 seconds ago 304 MB
unixhot/centos-ssh v1 ff1ab7d7e7f4 About an hour ago 304 MB
unixhot/centos latest 4edcb790dacf 3 hours ago 303 MB

4.构建容器

[root@linux-node1 ~]# docker run -d --name centos-ssh-supervisor -p 2222:22
unixhot/centos-ssh
9ebf53b3cacd093c11a9b5773c5fc62875626061f3f3fe0b5380013c78f2f15b

[root@linux-node1 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9ebf53b3cacd unixhot/centos-ssh "/usr/bin/supervisord" 6 seconds ago Up 3
seconds 0.0.0.0:2222->22/tcp centos-ssh-supervisor

5.使用ssh连接容器

[root@linux-node1 ~]# ssh root@192.168.56.11 -p 2222
root@192.168.56.11's password:
[root@9ebf53b3cacd ~]# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.0 117248 14668 ? Ss 07:25 0:00 /usr/bin/python /usr/bin/supervisord
-c /etc/supervisord.conf
root 9 0.0 0.0 82560 3608 ? S 07:25 0:00 /usr/sbin/sshd -D
root 25 1.2 0.0 139272 5428 ? Ss 07:26 0:00 sshd: root@pts/0
root 27 0.0 0.0 13376 1984 pts/0 Ss 07:27 0:00 -bash
root 40 0.0 0.0 49024 1808 pts/0 R+ 07:27 0:00 ps aux

操作系统标准化约定:

统一使用supervisor进行进程的管理

所有Docker容器,使用centos-ssh镜像时提供supervisor的ini配置文件。

运行环境镜像

现在有了系统镜像,当然文中的知识案例,具体的情况可以根据你所在企业的具体情况进行相关的配置,现在我们可以在系统镜像的基础上来构建运行环境。

Java 运行环境

Java环境在生产中非常常见,例如会启动一个单一的Java小进程处理队列里面的内容,只需要有JDK即可。那首先我们先构建一个只包含JDK的运行环境:

[root@linux-node1 ~]# cd /opt/dockerfile/runtime/
[root@linux-node1 runtime]# mkdir java

Java运行环境要基于centos-ssh的镜像来操作,所以先运行一个临时容器来构建Java运行环境,然后把操作步骤转换为Dockerfile。

[root@linux-node1 ~]# docker run --rm -it unixhot/centos-ssh /bin/bash
[root@ec2696c0f9f4 /]# yum install -y java-1.8.0-openjdk
java-1.8.0-openjdk-devel

使用yum安装的openjdk,默认可以不设置JAVA_HOME,即可执行相关的java程序。

1.编写Dockerfile

[root@linux-node1 runtime]# vim java/Dockerfile
# Docker for CentOS
#Base image
FROM unixhot/centos-ssh
#Who
MAINTAINER Jason.Zhao xxx@gmail.com
#Base pkg
RUN yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel && yum clean all
# JAVA_HOME
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
# Outside Port
EXPOSE 22
#supervisord start
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

2.构建镜像

[root@linux-node1 runtime]# docker build -t unixhot/runtime-java ./java/

3.查看镜像

[root@linux-node1 ~]# docker images | grep unixhot
unixhot/runtime-java latest ff3a2bb0b2a9 2 minutes ago 505.1 MB
unixhot/centos-ssh latest 02d375a33cd1 38 minutes ago 304 MB
unixhot/centos-ssh v1 ff1ab7d7e7f4 2 hours ago 304 MB
unixhot/centos latest 4edcb790dacf 4 hours ago 303 MB

当然十分可以使用,需要大家去运行一个小程序进行测试,这里就不演示了。

Tomcat运行环境

相对于单一使用Java命令启动Java服务,Tomcat

1.启动centos-ssh镜像的实例

[root@linux-node1 ~]# docker run --rm -it unixhot/centos-ssh /bin/bash
[root@80f529b965ef /]# yum install -y java-1.8.0-openjdk
java-1.8.0-openjdk-devel

为什么不直接使用Java的运行环境构建Tomcat?

首先,确实可以直接使用Java的运行环境来进行Tomcat的构建,但是会破坏我们系统层、运行环境层、业务层的架构,也就是将依赖关系复杂话了,这要根据企业自身情况来做。我先说说我的理由:

如果Tomcat使用的Java版本要升级到JDK 1.8版本,而Java运行环境的版本是1.7,不能升级,因为有很多服务就是在JDK 1.7的环境下开发的,未进行迁移。这个时候,如果Tomcat是基于Java 1.7的运行环境构建的,就出现依赖关系了。所以,仅仅是个人的建议:让问题简单化!

2.安装部署Tomcat 8

[root@80f529b965ef /]# cd /usr/local/src
[root@80f529b965ef src]# wget http://mirrors.cnnic.cn/apache/tomcat/tomcat-8/v8.5.6/bin/apache-tomcat-8.5.6.tar.gz
[root@80f529b965ef src]# tar zxf apache-tomcat-8.5.6.tar
[root@80f529b965ef src]# mv apache-tomcat-8.5.6 /usr/local/
[root@80f529b965ef src]# ln -s /usr/local/apache-tomcat-8.5.6/
/usr/local/tomcat

3.使用supervisor启动tomcat

[root@897cc10b8adf ~]# cd /etc/supervisord.d/
[root@897cc10b8adf supervisord.d]# vi tomcat.ini
[program:tomcat]
command=/usr/local/tomcat/bin/catalina.sh run
process_name=%(program_name)s
autostart=true
stdout_logfile_maxbytes=100MB
stdout_logfile_backups=10

更新supervisor并查看tomcat状态

[root@897cc10b8adf supervisord.d]# supervisorctl update
tomcat: stopped
tomcat: updated process group
[root@897cc10b8adf supervisord.d]# supervisorctl status
sshd RUNNING pid 408, uptime 0:06:00
tomcat RUNNING pid 704, uptime 0:00:03

4.准备Dockerfile的构建环境

现在我们开始编写Dockerfile,在编写之前,我们先决定一件事情,apache-tomcat的包,我们应该是像实验中使用wget进行下载并解压呢,还是应该提前将包放在宿主机,构建的时候使用Dockerfile ADD进行呢。

我建议选择后者,因为实际的工作中,我们通常要对Tomcat进行很多定制化的配置,例如进行安全规范的调整等。

这里我们能演示的就是直接下载,可以想象一下,这个已经是你修改过的软件包。

[root@linux-node1 ~]# cd /opt/dockerfile/runtime/
[root@linux-node1 runtime]# mkdir tomcat
[root@linux-node1 runtime]# cd tomcat/
[root@linux-node1 tomcat]# wget http://mirrors.cnnic.cn/apache/tomcat/tomcat-8/v8.5.6/bin/apache-tomcat-8.5.6.tar.gz

5.编写Dockerfile

# Docker for CentOS
#Base image
FROM unixhot/centos-ssh
#Who
MAINTAINER Jason.Zhao xxx@gmail.com
#Base pkg
RUN yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel && yum clean all
# JAVA_HOME
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
# Tomcat
ADD apache-tomcat-8.5.6.tar.gz /usr/local/
RUN ln -s /usr/local/apache-tomcat-8.5.6 /usr/local/tomcat
ADD tomcat.ini /etc/supervisord.d/tomcat.ini
ENV TOMCAT_HOME /usr/local/tomcat
# Outside Port
EXPOSE 22 8080
#supervisord start
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

6.构建tomcat镜像

[root@linux-node1 tomcat]# ls -l
total 9096
-rw-r--r-- 1 root root 9304958 Oct 6 16:39 apache-tomcat-8.5.6.tar.gz
-rw-r--r-- 1 root root 546 Oct 14 05:51 Dockerfile
-rw-r--r-- 1 root root 165 Oct 14 06:33 tomcat.ini
[root@linux-node1 tomcat]# docker build -t unixhot/runtime-tomcat .

7.查看镜像

[root@linux-node1 tomcat]# docker images | grep unixhot
unixhot/runtime-tomcat latest ef8372a88ad4 6 minutes ago 518.2 MB
unixhot/runtime-java latest ff3a2bb0b2a9 2 hours ago 505.1 MB
unixhot/centos-ssh latest 02d375a33cd1 3 hours ago 304 MB
unixhot/centos-ssh v1 ff1ab7d7e7f4 4 hours ago 304 MB
unixhot/centos latest 4edcb790dacf 6 hours ago 303 MB

8.构建tomcat-demo容器

[root@linux-node1 tomcat]# docker run -d --name tomcat-demo -p 88:8080 -p
89:22 unixhot/runtime-tomcat
8cea3ef85634210eb0cfab0f65a63b0ebd6961b5a67fc765b762785c01cd2c18
[root@linux-node1 tomcat]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8cea3ef85634 unixhot/runtime-tomcat "/usr/bin/supervisord" 5 seconds ago Up 2
seconds 0.0.0.0:89->22/tcp, 0.0.0.0:88->8080/tcp tomcat-demo

9.访问tomcat

http://192.168.56.11:88/

应用镜像

最上层的业务镜像就是在运行环境的基础上,直接使用或者根据业务情况再次进行二次定制。例如对于PHP运行环境,默认只安装基础通用的模块,对于业务需要的时候再次进行二次构建。这里我们拿一个比较简单的Jenkins来模拟。

Jenkins镜像构建

JenkinsJenkins是基于Java开发的一种持续集成工具,它有自己的yum安装方式,但是最直接的还是直接下载war包存放到tomcat目录下。

[root@linux-node1 ~]# cd /opt/dockerfile/app/
[root@linux-node1 app]# mkdir jenkins
[root@linux-node1 app]# cd jenkins/
[root@linux-node1 jenkins]# wget http://mirrors.jenkins-ci.org/war/latest/jenkins.war

2.编写Dockerfile

# Docker for CentOS
#Base image
FROM unixhot/runtime-tomcat
#Who
MAINTAINER Jason.Zhao xxx@gmail.com
# Jenkins
ADD jenkins.war /usr/local/tomcat/webapps/
# Outside Port
EXPOSE 22 8080
#supervisord start
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]

3.构建jenkins镜像

[root@linux-node1 jenkins]# docker build -t unixhot/jenkins .

4.查看镜像

[root@linux-node1 jenkins]# docker images | grep unixhot
unixhot/jenkins latest a7b16bc093ed 40 seconds ago 588.7 MB
unixhot/runtime-tomcat latest 3b596c9a7696 2 hours ago 518.8 MB
unixhot/runtime-java latest 476a6a2fc074 2 hours ago 505.8 MB
unixhot/centos-ssh latest d85aa8a9dfd4 3 hours ago 304.6 MB
unixhot/centos-ssh v1 3309208ed679 4 hours ago 300.9 MB
unixhot/centos latest 83f0491a30e1 4 hours ago 282.3 MB

5.创建jenkins-demo容器

[root@linux-node1 jenkins]# docker run -d --name jenkins-demo -p 91:22 -p
92:8080 unixhot/jenkins
6d88ba756befc84ef1820818994be028c12ac13825c2b439d680358d101e922e
[root@linux-node1 jenkins]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6d88ba756bef unixhot/jenkins "/usr/bin/supervisord" 7 seconds ago Up 2 seconds
0.0.0.0:91->22/tcp, 0.0.0.0:92->8080/tcp jenkins-demo

6.访问jenkins并进行初始化安装

当然如果你想构建一个启动后直接就可以使用的Jenkins,可以在安装完毕后,把刚才的容器重新提交成为镜像。

7.安装Jenkins并提交成为jenkins-login镜像。

进入镜像或者安装的密码,填入密码框并继续。后面步骤省略。全部安装默认即可。注意安装插件时时间会比较长。

[root@linux-node1 ~]# ./docker_in.sh jenkins-demo
[root@b3bbada66693 /]# cat /root/.jenkins/secrets/initialAdminPassword
b5257b8891464ebf890b38c00d24de71

获取Container ID:

[root@linux-node1 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3bbada66693 unixhot/jenkins "/usr/bin/supervisord" 9 minutes ago Up 9 minutes
0.0.0.0:91->22/tcp, 0.0.0.0:92->8080/tcp jenkins-demo

提交新的镜像

[root@linux-node1 ~]# docker commit -m "jenkins login" b3bbada66693
unixhot/jenkins-login
[root@linux-node1 ~]# docker images | grep jenkins
unixhot/jenkins-login latest c453363bb9f7 22 seconds ago 776.6 MB
unixhot/jenkins latest a7b16bc093ed 13 minutes ago 588.7 MB

8.使用jenkins-login镜像构建容器

现在可以使用的Jenkins容器诞生了,赶紧创建一个容器来进行使用吧。

[root@linux-node1 ~]# docker run -d --name jenkins-login -p 93:22 -p 94:8080
unixhot/jenkins-login
af421b4d5b076c756ab58ed8cc95c615a321f9517d30b755667d5d80d1336a63
[root@linux-node1 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
af421b4d5b07 unixhot/jenkins-login "/usr/bin/supervisord" 4 seconds ago Up 2
seconds 0.0.0.0:93->22/tcp, 0.0.0.0:94->8080/tcp jenkins-login

9.访问Jenkins容器,开始持续集成之路

Copyright © 赵班长@新运维社区 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-08-11 17:29:04

results matching ""

    No results matching ""