一、镜像概述

        Docker 镜像是Docker容器技术中的核心,也是应用打包构建发布的标准格式。一个完整的镜像可以支撑多个容器的运行,在Docker的整个使用过程中,进入一个已经定型的容器之后,就可以在容器中进行操作,最常见的操作就是在容器中安装应用服务。

如果想要把已经安装的服务容器进行迁移,就需要把环境以及部署的服务生成新的镜像。

二、镜像构建方式

1、基于已有的容器创建镜像

2、基于本地模板创建镜像

3、基于Dockerfile创建镜像

三、镜像构建案例

3.1、基于已有容器创建镜像

        基于现有镜像创建主要使用 docker commit 命令,即把一个容器里面运行的程序以及该程序的运行环境打包起来生成新的镜像。

命令格式:

docker commit [选项] 容器ID/名称 仓库名称:[标签] 常用选项:

  1. -m 说明信息;
  2. -a 作者信息;
  3. -p 生成过程中停止容器的运行。

        首先启动一个镜像,在容器里做相应的修改,然后将修改后的容器提交为新的镜像。需要记住该容器的ID号。

[root@localhost ~]# cat centos-7-x86_64.tar.gz | docker import - centos:7

sha256:1c5b0e27f83e10097555c6307ff9453d3ff32e2e2161803fec86263006d0a5a3



[root@docker ~]# docker run -it centos:7 /bin/bash

[root@d281f905fb30 /]# touch crushlinux #创建测试文件

[root@d281f905fb30 /]# exit

exit

[root@docker ~]# docker commit -m "crushlinux test images" -a "crushlinux" d281f905fb30 centos7:new

sha256:707ff266ae4df14df8f377a0bbb6715834f8d414d276a91982dab887e9333ca4

[root@docker ~]# docker images centos7:new

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

centos7             new                 707ff266ae4d        6 seconds ago       203MB

[root@docker ~]# docker run -it centos7:new /bin/bash

[root@8dea2626972f /]# ls -l crushlinux

-rw-r--r-- 1 root root 0 Jun  9 15:32 crushlinux

3.2基于本地模板创建镜像

        通过导入操作系统模板文件可以生成镜像,模板可以从 OPENVZ 开源项目下载,下载地址为 https://download.openvz.org/template/precreated/

下面是使用docker导入命令将下载的centos模板压缩包导入为本地镜像的例子。

​
[root@docker ~]# wget https://download.openvz.org/template/precreated/centos-7-x86_64.tar.gz

[root@docker ~]# ls -l centos-7-x86_64.tar.gz

-rw-r--r-- 1 root root 221692852 Jun 24  2016 centos-7-x86_64.tar.gz

[root@docker ~]# cat centos-7-x86_64.tar.gz | docker import - centos:test

sha256:14fbb0a4d45d550aad5fa7c2d25a0d40a87a23e0f5f24a95bd932ee9d8f13fec

[root@docker ~]# docker images centos:test

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

centos              test                14fbb0a4d45d        5 seconds ago       589MB

​

导入完成后,会返回生成镜像的 ID 信息。查看本地镜像列表时,可以看到新创建的镜像信息。

3.3、基于Dockerfile构建镜像

3.3.1、Docker 镜像结构

        镜像并不是一个单一的文件,而是由多层堆叠构成。可以通过docker history 命令查看镜像中各层的内容和大小,每层对应着Dockerfile 构建时的一条指令。Docker镜像默认存储在/var/lib/docker/<storage-driver>目录中。容器其实是在镜像的最上面加了一层读写层,在运行容器中做的任何文件改动,最终都会写到这个读写层。如果删除了容器,也就是删除了这个读写层,文件改动也就会丢失了。Docker使用存储驱动管理镜像每层内容及可读写层的容器层。

Docker镜像特点:

  1. Dockerfile中的每个指令都会创建一个新的镜像层;
  2. 镜像层可以被缓存和复用;
  3. 当Dockerfile中的指令被修改、复制的文件发生变化或者构建镜像时指定的变量值更换了,那么对应的镜像层缓存也将会失效;
  4. 某一层的镜像缓存失效,它之后的镜像层缓存都会失效;
  5. 镜像层是不可变的,如果在某一层中添加一个文件,然后在某一层中删除它,则镜像中依然会包含该文件,只是这个文件在Docker容器中不可见了。

3.3.2Dockerfile介绍

        Dockfile是一种可以被Docker程序解释的脚本,Dockerfile由多条的指令堆叠组成,每条指令都对应Linux下面的一条命令。Docker程序将这些Dockerfile指令翻译成真正的Linux 命令。Dockerfile有自己书写格式和支持的命令,Docker程序解决这些命令间的依赖关系,类似于源码软件中的Makefile。Docker程序将读取Dockerfile并根据指令生成定制的镜像。

        Dockerfile这种显而易见的脚本更容易被使用者接受,它明确的表明镜像是怎么产生的。有了Dockerfile当有定制额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成镜像即可。     

        Dockerfile 结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。Dockerfile 每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释。

3.3.3Dockerfile详解

        Dockerfile的指令根据作用可以分为两种,构建指令和设置指令。构建指令用于构建image,其指定的操作不会在运行image的容器上执行;设置指令用于设置image的属性,其指定的操作将在运行image的容器中执行。

1、FROM 镜像:Tag

        构建指令,必须指定且需要在Dockerfile文件中其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。

2、MAINTAINER 作者信息

        构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。

3、RUN 命令

        构建指令,RUN可以运行任何被基础image支持的命令并提交到新的镜像中。如基础image选择ubuntu,那么软件管理部分只能使用ubuntu的命令。

4、CMD [“要运行的程序” , ”参数1” , ”参数2”]

        设置指令,用于container(容器)启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次(最后一行),如果有多个CMD命令,则只执行最后一条。

5、ENTRYPOINT(设置container启动时执行的操作)

        设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。

6、USER 用户名/UID
设置指令,设置启动容器的用户,默认是root用户。
7、EXPOSE 端口

        设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不使用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。EXPOSE指令可以一次设置多个端口号,相应的运行容器的时候,可以配套的多次使用-p选项。

8、ENV 环境变量 变量值

构建指令,在image中设置一个环境变量。

设置了后,后续的RUN命令都可以使用,container启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:ENV JAVA_HOME /usr/local/java

9、ADD 源文件 目标文件

构建指令,所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0;如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>;如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。

10、COPY 源文件 目标文件

将源文件复制到目标文件,源文件要与Dockerfile位于相同目录中。

11、VOLUME  [“目录”]

设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。

12、WORKDIR 目录

设置指令相当于cd命令,为后续RUN,CMD,ENTRYPOINT指定工作目录。

13、ONBUILD 命令

指定所生产的镜像作为一个基础镜像时所要运行的命令

14、HEALTHCHECK

健康检查

        在编写 Dockerfile 时,有严格的格式需要遵循:第一行必须使用 FROM 指令指明所基于的镜像名称;之后使用 MAINTAINER 指令说明维护该镜像的用户信息;然后是镜像操作相关指令,如 RUN 指令。每运行一条指令,都会给基础镜像添加新的一层。最后使用 CMD 指令指定启动容器时要运行的命令操作。

3.3.4Dockerfile构建SSHD镜像

        基于Dockerfile制作镜像时首先需要建立工作目录,作为生成镜像的工作目录,然后分别创建并编写 Dockerfile文件、需要运行的脚本文件以及要复制到容器中的文件。

[root@docker ~]# iptables -F

[root@docker ~]# setenforce 0

[root@docker ~]# systemctl stop firewalld
关注DNS地址
[root@docker ~]# cat /etc/resolv.conf

# Generated by NetworkManager

nameserver 8.8.8.8

search localdomain

[root@docker ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens32

DNS1=8.8.8.8

[root@docker ~]# systemctl restart network

[root@docker ~]# systemctl restart docker
导入基础镜像
[root@docker ~]# cat centos-7-x86_64.tar.gz | docker import - centos:7

sha256:65adf0e2ab43e1a2cea98a7688e868e12aa332e24daef11340a04cde942f23e7
建立工作目录
[root@docker ~]# mkdir sshd

[root@docker ~]# ssh-keygen

[root@docker ~]# cp .ssh/id_rsa.pub sshd/

[root@docker ~]# cd sshd
编写Dockerfile文件
[root@docker sshd]# vim Dockerfile

#基于的基础镜像

FROM centos:7



#镜像作者信息

MAINTAINER Crushlinux <crushlinux@163.com>



#镜像执行的命令

RUN yum -y install openssh-server net-tools openssh-devel lsof telnet

RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config

RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key

RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key

ADD id_rsa.pub /root/.ssh/authorized_keys



#定义时区

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime



#开启 22 端口

EXPOSE 22



#启动容器时执行指令

CMD ["/usr/sbin/sshd" , "-D"]



[root@docker sshd]# ls

Dockerfile  id_rsa.pub
构建镜像
[root@docker sshd]# docker build -t sshd:new .

[root@docker sshd]# docker images sshd:new

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

sshd                new                 b8a5d106e704        2 minutes ago       683MB
测试容器
[root@docker sshd]# docker run -d -p 2222:22 --name sshd-test --restart=always sshd:new

89c847ca1333edb814de120eeb74abfeed5f6641bef107cf3eba93cc0c1bce03

[root@docker sshd]# ssh localhost -p 2222

The authenticity of host '[localhost]:2222 ([::1]:2222)' can't be established.

RSA key fingerprint is SHA256:YtJg2D1qUho3DhDpJCrZAhIKnOU98Ld6+k+zfamgQic.

RSA key fingerprint is MD5:d6:2e:97:0d:d0:33:e9:eb:d7:65:10:1c:57:cd:1a:0c.

Are you sure you want to continue connecting (yes/no)? yes

Warning: Permanently added '[localhost]:2222' (RSA) to the list of known hosts.

[root@89c847ca1333 ~]#

3.3.5Dockerfile构建httpd镜像

建立工作目录

[root@docker ~]# mkdir httpd

[root@docker ~]# cd httpd



编写Dockerfile文件

[root@docker httpd]# vim Dockerfile

FROM centos:7

MAINTAINER Crushlinux <crushlinux@163.com>



RUN yum -y install httpd

RUN mkdir -p /var/www/html

RUN echo "crushlinux" >/var/www/html/index.html

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime



EXPOSE 80

CMD ["httpd","-DFOREGROUND"]



构建镜像

[root@docker httpd]# docker build -t httpd:new .

[root@docker httpd]# docker images httpd

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

httpd               new                 381838e28ece        9 seconds ago       681MB



测试容器

[root@docker httpd]# docker run -d -p 8001:80 --name httpd-test --restart=always httpd:new

6f5d8980936a5d232e5f92b495b2b8fa0d7f70b17cdb73aa07e1ea5e6182d898

浏览器访问测试:http://192.168.200.111:8001

3.3.6Dockerfile构建nginx镜像

建立工作目录

[root@docker ~]# mkdir nginx

[root@docker ~]# cd nginx/



编写Dockerfile文件

[root@docker nginx]# vim run.sh

#!/bin/bash

/usr/local/nginx/sbin/nginx



[root@docker nginx]# vim Dockerfile

#基于的基础镜像

FROM centos:7



#镜像作者信息

MAINTAINER Crushlinux <crushlinux@163.com>



#安装相关依赖包

RUN yum install -y wget proc-devel net-tools gcc zlib zlib-devel make openssl-devel



#下载并解压nginx源码包

RUN wget http://nginx.org/download/nginx-1.19.0.tar.gz

RUN tar zxf nginx-1.19.0.tar.gz



#编译安装nginx

WORKDIR nginx-1.19.0

RUN ./configure --prefix=/usr/local/nginx && make && make install



#开启 80 和 443 端口

EXPOSE 80

EXPOSE 443



#修改 Nginx 配置文件,以非 daemon 方式启动

RUN echo "daemon off;">>/usr/local/nginx/conf/nginx.conf



#定义时区

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime



#复制服务启动脚本并设置权限

WORKDIR /root/nginx

ADD run.sh /run.sh

RUN chmod 775 /run.sh



#启动容器时执行脚本

CMD ["/run.sh"]



构建镜像

[root@docker nginx]# docker build -t nginx:new .

[root@docker nginx]# docker images nginx:new

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

nginx               new                 afd3b570434f        10 seconds ago      963MB



测试容器

[root@docker nginx]# docker run -d -p 8000:80 --name nginx-test --restart=always nginx:new

4b83c9c59a2f2e2b03473bd496f5006c24e05c4c342ad3b496d9fb7ba95b8b40

浏览器访问:http://192.168.200.111:8000

3.3.7Dockerfile构建Tomcat镜像

建立工作目录

[root@docker ~]# mkdir tomcat

[root@docker ~]# cd tomcat/

[root@docker tomcat]# ls

apache-tomcat-8.5.40.tar.gz  jdk-8u191-linux-x64.tar.gz

[root@docker tomcat]# tar xf jdk-8u191-linux-x64.tar.gz

[root@docker tomcat]# tar xf apache-tomcat-8.5.40.tar.gz



编写Dockerfile文件

[root@docker tomcat]# vim Dockerfile

FROM centos:7

MAINTAINER Crushlinux <crushlinux@163.com>



ADD jdk1.8.0_191 /usr/local/java

ENV JAVA_HOME /usr/local/java

ENV JAVA_BIN /usr/local/java/bin

ENV JRE_HOME /usr/local/java/jre

ENV PATH $PATH:/usr/local/java/bin:/usr/local/java/jre/bin

ENV CLASSPATH /usr/local/java/jre/bin:/usr/local/java/lib:/usr/local/java/jre/lib/charsets.jar



ADD apache-tomcat-8.5.40 /usr/local/tomcat

RUN chmod 755 /usr/local/tomcat/bin/startup.sh

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime



EXPOSE 8080



CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]



构建镜像

[root@docker tomcat]# docker build -t tomcat:new .

[root@docker ~]# docker images tomcat:new

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

tomcat              new                 6ab6dd78a7d1        8 minutes ago       1e+03MB



测试容器

[root@docker tomcat]# docker run -d -p 8080:8080 --name tomcat-test --restart=always tomcat:new

12c184900b42d2ae823ed8f03900bfe79c0a5ec205f10934c24fefa7292e4ed2

浏览器访问测试:http://192.168.200.111:8080

3.3.8Dockerfile构建MySQL镜像

建立工作目录

[root@docker ~]# mkdir mysql

[root@docker ~]# cd mysql/



编写Dockerfile文件

[root@docker mysql]# vim Dockerfile

FROM guyton/centos6

MAINTAINER Crushlinux <crushlinux@163.com>



RUN yum install -y mysql mysql-devel mysql-server

RUN /etc/init.d/mysqld start &&\

mysql -e "grant all privileges on *.* to 'root'@'%' identified by '123456';"&&\

mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by '123456';"

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime



EXPOSE 3306

CMD ["mysqld_safe"]



构建镜像

[root@docker mysql]# docker build -t mysql:new .

[root@docker mysql]# docker run -d -p 3306:3306 --name mysql-test --restart=always mysql:new

e97452d8693c6c0ed8e7adfe2a4d72af5d1b0330db2fec640ed9fb4030190048



测试容器

[root@docker mysql]# yum -y install mariadb mariadb-devel

[root@docker mysql]# mysql -h 192.168.200.111 -u root -P 3306 -p123456

Welcome to the MariaDB monitor.  Commands end with ; or \g.

Your MySQL connection id is 1

Server version: 5.1.73 Source distribution



Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.



Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.



MySQL [(none)]>

3.3.9、Dockerfile构建LNMP镜像

建立工作目录

[root@docker ~]# mkdir lnmp/

[root@docker ~]# cd lnmp/



编写Dockerfile文件

[root@docker lnmp]# vim Dockerfile

#基础镜像

FROM lemonbar/centos6-ssh



#维护该镜像的用户信息

MAINTAINER Crushlinux <crushlinux@163.com>



#配置Nginx 的YUM 源

RUN rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm



#安装nginx

RUN rpm --rebuilddb && yum -y install nginx



#修改nginx 配置文件,使之支持PHP

RUN sed -i '/^user/s/nginx/nginx\ nginx/g' /etc/nginx/nginx.conf

RUN sed -i '10cindex index.php index.html index.htm ;' /etc/nginx/conf.d/default.conf

RUN sed -i '30,36s/#//' /etc/nginx/conf.d/default.conf

RUN sed -i '31s/html/\/usr\/share\/nginx\/html/' /etc/nginx/conf.d/default.conf

RUN sed -i '/fastcgi_param/s/scripts/usr\/share\/nginx\/html/' /etc/nginx/conf.d/default.conf



#安装mysql 和php

RUN rpm --rebuilddb && yum -y install mysql mysql-devel mysql-server php php-mysql php-fpm



#修改php-fpm 配置文件允许nginx 访问

RUN sed -i '/^user/s/apache/nginx/g' /etc/php-fpm.d/www.conf

RUN sed -i '/^group/s/apache/nginx/g' /etc/php-fpm.d/www.conf



#mysql 数据库授权

RUN /etc/init.d/mysqld start &&\

mysql -e "grant all privileges on *.* to 'root'@'%' identified by '123456';" &&\

mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by '123456';"



#添加测试页面

ADD index.php /usr/share/nginx/html/index.php



#定义时区

RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime



#分别开启80 端口,443 端口,9000 端口,3360 端口

EXPOSE 80

EXPOSE 443

EXPOSE 9000

EXPOSE 3306



#复制脚本,设置权限,启动容器时启动该脚本

ADD run.sh /run.sh

RUN chmod 775 /run.sh

CMD ["/run.sh"]



[root@docker lnmp]# vim index.php

<?php

echo date("Y-m-d H:i:s")."<br />\n";

$link=mysql_connect("localhost","root","123456");

if(!$link) echo "FAILD!";

else echo "MySQL is OK!";

phpinfo();

?>



[root@docker lnmp]# vim run.sh

#!/bin/bash

/etc/init.d/nginx start && /etc/init.d/php-fpm start && /usr/bin/mysqld_safe



[root@docker lnmp]# ls

Dockerfile  index.html  run.sh



构建镜像

[root@docker lnmp]# docker build -t lnmp:new .

[root@docker lnmp]# docker images lnmp

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

lnmp                new                 23efdeac6bee        37 minutes ago      675MB



测试容器

[root@docker ~]# docker rm -f $(docker ps -aq)

12c184900b42

e97452d8693c

4b83c9c59a2f

89c847ca1333

[root@docker lnmp]# docker run -d -p 80:80 -p 3306:3306 -p 9000:9000 --name lnmp-test --restart=always lnmp:new

18f902a0103f8067c4fd7fb3d169934d9f65ab0bc7edd9da49d4c071645ae7c8

浏览器访问测试:http://192.168.200.111

3.3.10、Dockerfile构建Redis镜像

建立工作目录

[root@docker ~]# mkdir redis

[root@docker ~]# cd redis/



编写Dockerfile文件

[root@docker redis]# vim Dockerfile

FROM centos:7

MAINTAINER Crushlinux <crushlinux@163.com>



RUN yum -y update && yum -y install epel-release && yum -y install redis

RUN sed -i -e 's@bind 127.0.0.1@bind 0.0.0.0@g' /etc/redis.conf

RUN sed -i -e 's@protected-mode yes@protected-mode no@g' /etc/redis.conf

RUN echo "requirepass 123456" >> /etc/redis.conf



RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

EXPOSE 6379



CMD [ "/usr/bin/redis-server","/etc/redis.conf"]



构建镜像

[root@localhost redis]# docker build -t redis:new .

[root@localhost redis]# docker images redis:new

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

redis               new                 b44d5cde2bf2        9 seconds ago       368MB



测试容器

[root@localhost redis]# docker run -d -p 6379:6379 --name redis-test --restart=always redis:new

d22e8e95eebff080e1bea758634ac43fe7ee9ecd810d5be6f08a5da9b585b7b1



[root@localhost redis]# rpm -ivh /root/epel-release-latest-7.noarch.rpm

[root@localhost redis]# yum -y install redis

[root@localhost redis]# redis-cli -h localhost -a 123456

localhost:6379> exit

更多推荐