Docker镜像与制作(二)

Docker镜像有没有内核?

从镜像大小上即可看出,Docker镜像是没有内核的,一个内核的大小远大于精简版镜像,镜像本身只提供rootfs,即系统启动后,用户空间里使用的文件系统,如/dev,/bin,/etc等目录,所以容器里没有/boot目录,/boot目录里保存的是与内核相关的文件与目录。
 root@docker1 ~]#./docker-in.sh 61f0542dc08
root@61f0542dc08d:/# uname -r
4.15.0-29-generic
root@61f0542dc08d:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@61f0542dc08d:/# ls -a /boot    空目录
...
没有内核是因为当容器启动和运行时,直接使用宿主机内核,其没有直接与系统硬件打交道,所以也就不需要内部有内核和硬件驱动。宿主机上跑的带内核的系统是虚拟机。

镜像打造

两种方法:手动打造 OR 自动打造(基于Dockerfile)

手动制作yum版nginx镜像:

Docker制作类似于虚拟机镜像的制作,按照公司的实际业务需求,将需要安装的软件、相关配置文件等基础环境配置完成,打成镜像。最后在批量从镜像生成批量生产实例,大大简化了相同环境的重复部署工作。

初始化系统:

基于本地docker仓库有centos镜像,然后进行打造镜像

# docker run -d -it --name centos-yum centos /bin/bash
[root@fc244bec114b /]# yum install wget -y
[root@fc244bec114b /]# cd /etc/yum.repo.d/
[root@fc244bec114b yum.repos.d]# rm -rf ./*     #更换yum源为阿里云
[root@fc244bec114b yum.repos.d]# wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@fc244bec114b yum.repos.d]# wget -O epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

yum安装并配置nginx:

[root@fc244bec114b /]# yum install nginx -y

安装常用命令:
#yum install vim pcre pcre-devel zlib \
zlib-devel openssl openssl-devel iproute net-tools iotop -y

修改nginx配置文件
# vim /etc/nginx/nginx.conf     #修改或添加如下:
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
daemon off;     禁止后台运行

自定义web页面
# vim /usr/share/nginx/html/index.html
<h1>Welcome to my web site!!!</h1>

提交为镜像:

在宿主机基于容器 ID 提交为镜像;可带TAG号,可以更好的区分公司业务。

#docker commit -m "nginx image" -a "martinhe 384430592@qq.com" "fc244bec114b" centos-nginx:v1

此项仅供参考,因上述容器内已经修改dameon off,使用如下命令打造的镜像,启动容器时报错:
nginx: [emerg] "daemon" directive is duplicate in /etc/nginx/nginx.conf:9
#docker commit -m "nginx image" -a "martinhe 384430592@qq.com" -c 'CMD ["/usr/sbin/nginx","-g","daemon off;"]'  "fc244bec114b" centos-nginx:v2

Usage:  docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
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)

从打造的镜像起一个名为yum-nginx-centos的容器

#docker run -d -p 80:80  --name yum-nginx-centos centos-nginx:v1 /usr/sbin/nginx

访问测试:

DockerFile制作yum安装nginx版镜像

DockerFile可以说是一种可以被 Docker 程序解释的脚本, DockerFile是由一条条的命令组成的,每条命令对应 linux下面的一条命令, Docker程序将这些命令放到容器内去执行。Docker 程序读取 DockerFile 并根据指令生成 Docker镜像。有了Dockerfile后,可以更加方便的打造镜像,通过修改Dockerfile内的命令,即可打造不同业务需求的镜像。避免枯燥无味的手动打造镜像。具体如下:

初始化系统:

基于本地docker仓库有centos镜像,然后进行打造镜像

创建目录环境:
# cd /opt
# mkdir dockerfile/{web/{nginx,tomcat,jdk,apache},system/{centos,ubuntu,redhat}} -pv    #可根据业务需求后续创建不同的文件夹。

进入nginx目录:
# cd /opt/dockerfile/web/nginx

编写 Dockerfile
# vim Dockerfile
# Martinhe Dockerfile
# Base centos Create nginx-image
FROM centos[:latest]        #除注释外,第一行定义基础镜像,本地镜像名,若不存在从官网拉取
MAINTAINER Martin.he 384430592@qq.com   #定义镜像维护者信息
#USER nginx:nginx
#WORKDIR /a
#WORKDIR b     指定工作目录,最终工作目录为/a/b
#VOLUME ["/dir_1","/dir_2"..]      #设定宿主机目录对应容器内目录。
#ENV CATALINA_HOME /usr/local/tomcat   #设定环境变量,可拷贝脚本到容器内指定目录
#ENV PATH ${CATALINA_HOME}/bin:$PATH
# 安装常用命令
RUN yum install wget -y && cd /etc/yum.repos.d/ && rm -rf ./* && wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O
epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && yum install nginx vim pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-to
ols iotop -y
# 部署网站或应用源码包,ADD命令拷贝到设定目录内自动解压
ADD code.tar.gz /usr/share/nginx/html/
# copy本地脚本到根目录
#COPY nginx.sh /
#COPY nginx.conf /etc/nginx/
# 通常使用daemon off。进行容器卡位。即容器内PID为1的应用为nginx
#CMD ["/usr/sbin/nginx","-g","daemon off;"]
CMD /usr/sbin/nginx -g "daemon off;"
#CMD /nginx.sh

#如果要拷贝脚本到目录内执行,在本地提前赋予执行权限:
#vim nginx.sh
#!/bin/bash
/usr/sbin/nginx
tail -f /etc/hosts

#chmod +x nginx.sh

执行镜像构建:

可清晰看到每个执行步骤:
[Sat Jul 06 21:36
 root@docker1 /opt/dockerfile/web/nginx]#docker build -t martinhe/nginx:v5 .
Sending build context to Docker daemon  8.704kB
Step 1/5 : FROM centos
 ---> 9f38484d220f
Step 2/5 : MAINTAINER Martin.he 384430592@qq.com
 ---> Using cache
 ---> 5fb8e2538ace
Step 3/5 : RUN yum install wget -y && cd /etc/yum.repos.d/ && rm -rf ./* && wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && yum install nginx vim pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop -y
 ---> Using cache
 ---> 2f605d407fcf
Step 4/5 : ADD code.tar.gz /usr/share/nginx/html/
 ---> Using cache
 ---> 3875c709a39e
Step 5/5 : CMD /usr/sbin/nginx -g "daemon off;"
 ---> Running in b745a9660fbc
Removing intermediate container b745a9660fbc
 ---> 881d2a4d347f
Successfully built 881d2a4d347f
Successfully tagged martinhe/nginx:v5

查看是否生成本地镜像:

从镜像启动容器:

#docker run -d -it -p 80:80 martinhe/nginx:v6

规划镜像制作方案:

制作镜像时,可基于基础镜像制作相关服务基础镜像,而后再制作代码发布镜像,如下图:

预先准备相关文件夹:

# mkdir /opt/dockerfile/{system,web/{nginx/mknginx,jdk/8u192,haproxy,tomcat/{tomcat-app1,tomcat-app2},apache} -pv

制作centos基础镜像:

安装系统常用命令和应用程序。
Dockfile文件内容:
# Martinhe Dockerfile
# Base centos-7.6.1810 and yum some frequently used command and packages
FROM centos:7.6.1810
MAINTAINER Martin.he 384430592@qq.com
RUN yum install wget -y && cd /etc/yum.repos.d/ && mkdir backup && cp Cent* backup && wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && yum install  vim iotop bc gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl  openssl-devel zip unzip zlib-devel  net-tools lrzsz tree ntpdate telnet lsof tcpdump wget libevent libevent-devel bc  systemd-devel bash-completion traceroute -y
build-command.sh文件内容:
#!/bin/bash
TAG=7.6.1810
docker build -t martinhe/centos:${TAG} .

制作编译安装nginx镜像:

Dockfile文件内容:
# Martinhe Dockerfile
# Base martinhe/centos:7.6.1810 Create nginx-image
FROM martinhe/centos:7.6.1810
MAINTAINER Martin.he 384430592@qq.com
RUN yum install wget -y && cd /etc/yum.repos.d/ && rm -rf ./* && wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && wget -O epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && yum install vim pcre pcre-devel zlib zlib-devel openssl openssl-devel iproute net-tools iotop -y
RUN yum install gcc gcc-c++ -y
ADD nginx-1.14.2.tar.gz /usr/local/
RUN cd /usr/local/nginx-1.14.2 && ./configure --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module && make -j 2 && make install && ln -sv /apps/nginx/sbin/nginx /usr/sbin/nginx
COPY nginx.conf /apps/nginx/conf
RUN mkdir /data/htdocs/ -pv  && groupadd -g 666 nginx && useradd -u 666 -g 666 -r -s /sbin/nologin nginx
ADD code.tar.gz /data/htdocs/
RUN chown nginx.nginx -R /data/htdocs && chown nginx.nginx -R /apps/nginx/
CMD /usr/sbin/nginx
nginx.conf文件内容:

user nginx nginx; worker_processes 1; daemon off; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /data/htdocs; index index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }
index.html和code.tar.gz文件内容:

需要部署的网页文件压缩包

<h1>Welcome to my web make install nginx site!!!</h1>

# tar zcvf code.tar.gz index.html
build-command.sh文件内容:
#!/bin/bash
TAG=1.14.2
docker build -t martinhe/nginx:${TAG} .

制作二进制安装haproxy镜像:

Dockfile文件内容:
# Martinhe Dockerfile
# Base martinhe/centos:7.6.1810 Create haproxy-image
FROM martinhe/centos:7.6.1810
MAINTAINER Martin.he 384430592@qq.com
ADD haproxy-1.8.20.tar.gz /usr/local/src/
RUN cd /usr/local/src/haproxy-1.8.20 && make ARCH=x86_64 TARGET=linux2628 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 && ln -s /usr/local/haproxy/sbin/haproxy /usr/sbin/
COPY haproxy.cfg /etc/haproxy/
COPY haproxy.sh /usr/local/haproxy/run/
RUN groupadd -g 777 haproxy && useradd -u 777 -g 777 -r -s /sbin/nologin haproxy
RUN chown haproxy.haproxy -R /usr/local/haproxy
CMD /usr/local/haproxy/run/haproxy.sh
haproxy.cfg文件内容:
global
maxconn 100000
chroot /usr/local/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 777
gid 777
daemon
nbproc 1
#cpu-map 1 0
#cpu-map 2 1
#cpu-map 3 2
#cpu-map 4 3
pidfile /usr/local/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info

defaults
option http-keep-alive
option  forwardfor
maxconn 100000
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:q1w2e3r4

listen  web_port
 bind 0.0.0.0:80
 mode http
 log global
 server web1  172.16.36.20:80  check inter 3000 fall 2 rise 5
haproxy.sh文件内容:

用脚本运行haproxy,并在容器中前台打开文件的方式,使容器在后台持续运行不退出

#!/bin/bash
haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
build-command.sh文件内容:
#!/bin/bash
TAG=1.18.20
docker build -t martinhe/haproxy:${TAG} .

制作二进制安装jdk基础镜像:

Dockfile文件内容:
# Martinhe Dockerfile
# Base martinhe/centos:7.6.1810 Create jdk-8u192-image
FROM martinhe/centos:7.6.1810
MAINTAINER Martin.he 384430592@qq.com
ADD jdk-8u192-linux-x64.tar.gz /usr/local/
RUN cd /usr/local/ && ln -s jdk1.8.0_192 java
COPY jdk.sh /etc/profile.d/
jdk.sh 文件内容:

配置内部JAVA环境变量

export JAVA_HOME=/usr/local/java/
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH
build-command.sh文件内容:
#!/bin/bash
TAG=8u192
docker build -t martinhe/jdk:${TAG} .

制作二进制安装tomcat基础镜像:


Dockfile文件内容:
# Martinhe Dockerfile
# Base martinhe/centos:7.6.1810 Create jdk-8u192-image
FROM martinhe/jdk:8u192
MAINTAINER Martin.he 384430592@qq.com
ADD apache-tomcat-8.5.42.tar.gz /usr/local/
RUN cd /usr/local/ && ln -s apache-tomcat-8.5.42 tomcat && mkdir /data/webapps/ROOT/{WEN-INF,META-INF,classes,lib} -p && groupadd -g 888 tomcat && useradd -u 888 -g 888 -d /home/tomcat -r tomcat && cp /usr/local/tomcat/conf/server.xml{,.bak}
COPY server.xml /usr/local/tomcat/conf
COPY tomrun.sh /usr/local/tomcat/bin
RUN chown tomcat.tomcat -HR /usr/local/tomcat && chown tomcat.tomcat -R /data/webapps
COPY tomcat.sh /etc/profile.d/
CMD /usr/local/tomcat/bin/tomrun.sh
修改server.xml文件web默认存储目录内容:
      <Host name="localhost"  appBase="/data/webapps"
            unpackWARs="true" autoDeploy="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

      </Host>
tomcat.sh 文件内容:

配置内部tomcat环境变量

export CATALINA_HOME=/usr/local/tomcat
export PATH=$CATALINA_HOME/bin:$PATH
tomrun.sh 文件内容:
#!/bin/bash
su - tomcat -c "/usr/local/tomcat/bin/catalina.sh run"
build-command.sh文件内容:
#!/bin/bash
TAG=8.5.42
docker build -t martinhe/tomcat:${TAG} .

制作二进制安装tomcat-app1镜像:

Dockfile文件内容:
# Martinhe Dockerfile
# Base martinhe/centos:7.6.1810 Create tomcat-webapp1-image
FROM martinhe/tomcat:8.5.42
MAINTAINER Martin.he 384430592@qq.com
ADD code.tar.gz /data/webapps/ROOT
RUN chown tomcat.tomcat /data/webapps -R
index.jsp 文件内容:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!DOCTYPE html>
<html>
    <head>
                <meta charset="utf-8">
                <title>Web app1</title>
    </head>
    <body>
            后面的内容是服务器端动态生成字符串,最后拼接在一起
            <%
            out.println("hello app1.jsp");
            %>
    </body>
</html>

# tar zcvf code.tar.gz index.jsp
build-command.sh文件内容:
#!/bin/bash
TAG=app1
docker build -t martinhe/tomcat:${TAG} .

最终的目录结构是这样的: