Docker镜像可以通过Docker hub或者阿里云等仓库中获取,这些镜像是由官方或者社区人员提供的,对于Docker用户来说并不能满足我们的需求,但是从无开始构建镜像成本大。常用的数据库、中间件、应用软件等都有现成的Docker官方镜像或社区创建的镜像,我们只需要稍作配置就可以直接使用。 使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为Docker的工程师知道如何更好的在容器中运行软件。 当然,某些情况下我们也不得不自己构建镜像,比如找不到现成的镜像,比如自己开发的应用程序,需要在镜像中加入特定的功能。
Docker提供了三种构建镜像的方法:
(1) docker commit命令
(2) 基于本地模板导入
(3) Dockerfile构建文件
docker commit命令可以基于容器创建镜像,创建过程大致分为三步,先创建容器,在容器中安装我们所需要的内容,再使用docker commit将容器打包为镜像即可 ## 基于本地模板导入 用户可以直接从一个操作系统模板文件导入一个镜像,主要使用 docker [container] import 命令。命令 格式为 docker [image] import [OPTIONS] file|URL|-[REPOSITORY[:TAG]] ,要直接导入一个镜像,可以使用 OpenVZ 提供的模板来创建,或者用其他已导入的镜像模板来创建。OpenVZ 模板的下载地址为 http://openvz.org/Download/templates/precreated。
Dockerfile
(1)基本概念
Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是Dockerfile。 Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile上添加或者修改指令,重新生成镜像即可,省去了敲命令的麻烦。
(2)文件格式 Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动执行指令。一开始必须要指明所基于的镜像名称,接下来一般会说明维护者信息;后面则是镜像操作指令,例如ADD指令。每执行一条ADD指令,镜像添加新的一层,并提交;最后是CMD指令,来指明运行容器时的操作命令。
dockerfile语法
Dockerfile是由一系列指令和参数构成的脚本,一个Dockerfile里面包含了构建整个镜像的完整指令。Docker通过docker build执行Dockerfile中的一系列指令自动构建镜像,常用的Dockerfile指令有以下几种:
1、FROM指令必须为Dockerfile文件开篇的第一个非注释行,用于指定构建镜像所使用的基础镜像,后续的指令运行都要依靠此基础镜像所提供的的环境。实际使用中,如果没有指定仓库,docker build会先从本机查找是否有此基础镜像,如果没有会默认去Docker Hub Registry上拉取,再找不到就会报错,格式如下:
ROM [:] FROM @
#Digest:镜像的哈希码,防止镜像被冒名顶替。
2、MAINTAINER指令用于让Dockerfile的作者提供个人的信息,Dockerfile并不限制MAINTAINER指令的位置,但是建议放在FROM指令之后,在较新的Docker版本中,已经被LABEL替代,格式如下。
MAINTAINER “[email protected]”
3、BEL指令用于让用户为镜像指定各种元数据(键值对的格式),格式如下。
LABEL = =
4、COPY指令用于复制宿主机上的文件到目标镜像中,格式如下。
COPY ...
COPY ["",... ""]
:要复制的源文件或者目录,支持通配符 :目标路径,即正创建的镜像的文件系统路径,建议使用绝对路径,否则,COPY指令
会以WORKDIR为其起始路径。如果路径中如果包含空白字符,建议使用第二种格式用引号引起来,否则会被当成两个文件。
5、ADD指令跟COPY类似,不过它还支持使用tar文件和URL路径。当拷贝的源文件是tar文件时,
会自动展开为一个目录并拷贝进新的镜像中;然而通过URL获取到的tar文件不会自动展开。主机可
以
再联网的情况下,docker build可以将网络上的某文件引用下载并打包到新的镜像中,格式如下。
ADD ...
ADD ["",... ""]
6、WORKDIR指令用于指定工作目录,可以指多个,每个WORKDIR只影响他下面的指令,直到遇
见下一个WORKDIR为止。WORKDIR也可以调用由ENV指令定义的变量。,格式如下。
WORKDIR 相对路径或者绝对路径
7、VOLUME指令用于在镜像中创建一个挂载点目录。Volume有两种类型:绑定挂载卷和docker管
理的卷。在Dockerfile中只支持Docker管理的卷,也就是说只能指定容器内的路径,不能指定宿主
机的路径,格式如下。
VOLUME
VOLUME [""]
8、EXPOSE指令用于指定容器中待暴露的端口。比如容器提供的是一个https服务且需要对外提供
访问,那就需要指定待暴露443端口,然后在使用此镜像启动容器时搭配P的参数才能将待暴露的
状态转换为真正暴露的状态,转换的同时443也会转换成一个随机端口,跟p :443一个意思。
EXPOSE指令可以一次指定多个端口
例如:EXPOSE 11111/udp 11112/tcp,格式如下。
EXPOSE [/] [[/] ...]
9、ENV指令用于为镜像定义所需的环境变量,并可被ENV指令后面的其它指令所调用。调用格式
为 或者{variable_name},使用docker run启动容器的时候加上e的参数为
variable_name赋值,可以覆盖Dockerfile中ENV指令指定的此variable_name的值。但是不会影响
到Dockerfile中已经引用过此变量的文件名,格式如下。
ENV
ENV = ...
10、RUN指令运行于docker build过程中运行的程序,可以是任何命令。RUN指令后所执行的命令
必须在FROM指令后的基础镜像中存在才行,格式如下。
RUN
RUN ["executable", "param1", "param2"]
通常是一个shell命令,系统默认会把后面的命令作为shell的子进程来运行,以”/bin/sh c”来运行
它。
第二种格式的参数是一个JSON格式的数组,其中”executable”为要运行的命令,后面
的”paramN”为传递给命令的选项或参数。
11、CMD指令用于用户指定启动容器的默认要运行的程序,也就是PID为1的进程命令,且其运行
结束后容器也会终止。如果不指定,默认是bash。CMD指令指定的默认程序会被docker run命令行
指定的参数所覆盖。Dockerfile中可以存在多个CMD指令,但仅最后一个生效。因为一个Docker容
器只能运行一个PID为1的进程。类似于RUN指令,也可以运行任意命令或程序,但是两者的运行时
间点不同。RUN指令运行在docker build的过程中,而CMD指令运行在基于新镜像启动容器时,格式如下。
CMD command param1 param2
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
前两种语法格式同RUN指令。第一种用法对于CMD指令基本没有意义,因为它运行的程序PID不为
1。
第三种则需要结合ENTRYPOINT指令使用,CMD指令后面的命令作为ENTRYPOINT指令的默认参
数。如果docker run命令行结尾有参数指定,那CMD后面的参数不生效。
12、ENTRYPOINT指令类似CMD指令的功能,用于为容器指定默认运行程序。Dockerfile中可以存
在多个ENTRYPOINT指令,但仅最后一个生效,与CMD区别在于,由ENTRYPOINT启动的程序不
会被docker run命令行指定的参数所覆盖,而且这些命令行参数会被当做参数传递给ENTRYPOINT
指令指定的程序,格式如下。
ENTRYPOINT command param1 param2
ENTRYPOINT ["executable", "param1", "param2"]
不过,docker run的–entrypoint选项的参数可覆盖ENTRYPOINT指定的默认程序。
13、USER用于指定docker build过程中任何RUN、CMD等指令的用户名或者UID。默认情况下容器
的运行用户为root,格式如下。
SER [:]
USER [:]
1.将Centos-7 . repo 、 epel-7 . repo 文件拖进虚拟机
[root@yhm2 ~]# ll
total 12
-rw-------. 1 root root 1092 Jun 27 14:57 anaconda-ks.cfg
-rw-r--r--. 1 root root 2523 Aug 30 20:53 Centos-7.repo
-rw-r--r--. 1 root root 664 Aug 30 20:53 epel-7.repo
2.部署dockerfile
[root@yhm2 ~]# vim dockerfile
[root@yhm2 ~]# cat dockerfile
FROM centos:7
MAINTAINER [email protected]
ADD Centos-7.repo /etc/yum.repos.d/
ADD epel-7.repo /etc/yum.repos.d/
RUN yum install -y nginx
EXPOSE 80
CMD ["/usr/sbin/nginx","-g","daemon off;"]
3.构建镜像,镜像名称为nginx:v1
[root@yhm2 ~]# docker build -t nginx:z1 .
Successfully built ba8c364be5b4
Successfully tagged nginx:z1
4.运行容器 ,映射端口为88:80
[root@yhm2 ~]# docker run -d --name yuhemiao -p 88:80 nginx:z1
c0d18444caec04443f2b43e50c11ecb66a0b394a7fd28fe0438b47bb68f02d13
[root@yhm2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c0d18444caec nginx:z1 "/usr/sbin/nginx -g …" 6 seconds ago Up 5 seconds 0.0.0.0:88->80/tcp, :::88->80/tcp yuhemiao
[root@yhm2 ~]# docker exec -it yuhemiao /bin/bash
[root@c0d18444caec /]# cd /usr/share/nginx/html/
[root@c0d18444caec html]# ll
total 12
-rw-r--r--. 1 root root 3650 Oct 18 2021 404.html
-rw-r--r--. 1 root root 3693 Oct 18 2021 50x.html
lrwxrwxrwx. 1 root root 20 Aug 30 17:41 en-US -> ../../doc/HTML/en-US
drwxr-xr-x. 2 root root 27 Aug 30 17:41 icons
lrwxrwxrwx. 1 root root 18 Aug 30 17:41 img -> ../../doc/HTML/img
lrwxrwxrwx. 1 root root 25 Aug 30 17:41 index.html -> ../../doc/HTML/index.html
-rw-r--r--. 1 root root 368 Oct 18 2021 nginx-logo.png
lrwxrwxrwx. 1 root root 14 Aug 30 17:41 poweredby.png -> nginx-logo.png
5.进入容器,删除默认网页,写入新的默认网页
[root@c0d18444caec html]# rm -rf index.html
[root@c0d18444caec html]# ls
404.html en-US img poweredby.png
50x.html icons nginx-logo.png
[root@c0d18444caec html]# echo yuhemiao > index.html
[root@c0d18444caec html]# ls
404.html en-US img nginx-logo.png
50x.html icons index.html poweredby.png
做前准备
1.在一号虚拟机下载httpd并设置开机自启
[root@yhm1 ~]# mount /dev/cdrom /mnt/
mount: /mnt: WARNING: device write-protected, mounted read-only.
[root@yhm1 ~]# yum -y install httpd
[root@yhm1 ~]# systemctl enable --now httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
2.上传扫雷的软件包
[root@yhm1 ~]# cd /var/www/html/
[root@yhm1 html]# yum install -y lrzsz
[root@yhm1 html]# rz -E
rz waiting to receive.
[root@yhm1 html]# ll
total 244
-rw-r--r--. 1 root root 247278 Aug 30 20:53 saolei.zip
3.防火墙
[root@yhm1 ~]# systemctl stop firewalld
[root@yhm1 ~]# systemctl disable firewalld
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@yhm1 ~]# vim /etc/selinux/config
...
SELINUX=disabled
...
1.在二号虚拟机上下载lrzsz,将Centos-7 . repo 、 epel-7 . repo 文件拖进虚拟机
[root@yhm2 ~]# yum -y install lrzsz
[root@yhm2 ~]# rz -E
rz waiting to receive.
[root@yhm2 ~]# rz -E
rz waiting to receive.
[root@yhm2 ~]# ll
total 12
-rw-------. 1 root root 1092 Jun 27 14:57 anaconda-ks.cfg
-rw-r--r--. 1 root root 2523 Aug 30 20:53 Centos-7.repo
-rw-r--r--. 1 root root 664 Aug 30 20:53 epel-7.repo
2.编辑dockerfile
[root@yhm2 ~]# vim Dockerfile
[root@yhm2 ~]# cat Dockerfile
FROM centos:7
MAINTAINER [email protected]
ADD Centos-7.repo /etc/yum.repos.d/
ADD epel-7.repo /etc/yum.repos.d/
RUN yum install -y tomcat unzip curl
WORKDIR /var/lib/tomcat/webapps/
RUN curl -O http://192.168.223.144/saolei.zip && \
unzip saolei.zip && \
mv saolei ROOT
ADD init.sh /init.sh
EXPOSE 8080
CMD ["/bin/bash","/init.sh"]
[root@yhm2 ~]# vim init.sh
[root@yhm2 ~]# cat init.sh
#!/bin/bash
/usr/libexec/tomcat/server start
3.构建镜像
[root@yhm2 ~]# docker build -t saolei:z1 .
Successfully built fe682460e4a1
Successfully tagged saolei:z1
4.运行容器
[root@yhm2 ~]# docker run -d --name yuhemiao -p 8081:8080 saolei:z1
976a6d90b47009128aae9f4ffde8ce911868735d5fb23d52176cd18dbbbaeef9
[root@yhm2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
976a6d90b470 saolei:z1 "/bin/bash /init.sh" 3 seconds ago Up 3 seconds 0.0.0.0:8081->8080/tcp, :::8081->8080/tcp yuhemiao
1.将kodexplo re r4.40.zi p 和 nginx . txt 文件拖至该虚拟机中
[root@yhm2 ~]# ll
total 13588
-rw-------. 1 root root 1092 Jun 27 14:57 anaconda-ks.cfg
-rw-r--r--. 1 root root 2523 Aug 30 20:53 Centos-7.repo
-rw-r--r--. 1 root root 664 Aug 30 20:53 epel-7.repo
-rw-r--r--. 1 root root 13894810 Aug 30 20:54 kodexplorer4.40.zip
-rw-r--r--. 1 root root 523 Aug 30 20:54 nginx.txt
2.创建/opt/dockerfile/kod目录,将所需的软件包和文件放置该目录下
[root@yhm2 ~]# mkdir -p /opt/dockerfile/kod/
[root@yhm2 ~]# cd /opt/dockerfile/kod/
[root@yhm2 kod]# cp /root/* /opt/dockerfile/kod/
[root@yhm2 kod]# mv nginx.txt nginx.conf
[root@yhm2 kod]# ls
anaconda-ks.cfg epel-7.repo nginx.conf
Centos-7.repo init.sh
Dockerfile kodexplorer4.40.zip
3.在该目录下编辑dockerfile,使用基础镜像centos:7
[root@yhm2 kod]# vim dockerfile
[root@yhm2 kod]# cat dockerfile
FROM centos:7
ADD Centos-7.repo /etc/yum.repos.d/
ADD epel-7.repo /etc/yum.repos.d/
RUN yum -y install nginx php-fpm php-gd php-mbstring unzip && \
sed -i '/^user/c user=nginx' /etc/php-fpm.d/www.conf && \
sed -i '/^group/c group=nginx' /etc/php-fpm.d/www.conf
COPY nginx.conf /etc/nginx/nginx.conf
RUN mkdir /code
WORKDIR /code
COPY kodexplorer4.40.zip .
RUN unzip kodexplorer4.40.zip && \
chown -R nginx.nginx .
ADD init.sh /init.sh
EXPOSE 80
ENTRYPOINT ["/bin/bash","/init.sh"]
[root@yhm2 kod]# vim init.sh
[root@yhm2 kod]# cat init.sh
#!/bin/bash
php-fpm -D
echo "$1" >> /etc/nginx/nginx.conf
nginx -g 'daemon off;'
4.构建镜像kod:v1
[root@yhm2 kod]# docker build -t kod:v1 .
Successfully built 2b46ed5e2e87
Successfully tagged kod:v1
5.运行容器,指定映射端口80:80
[root@yhm2 kod]# docker run -d --name yuhemiao -p 80:80 kod:v1
09611bd1d4f21dcc3a7e33d2fcd2bc688f5c0dbda064ef33d0d10611b200a42f
[root@yhm2 kod]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
09611bd1d4f2 kod:v1 "/bin/bash /init.sh" 7 seconds ago Up 6 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp yuhemiao