目录
1、详解Dockerfile制作镜像之——命令讲解
参考资料:
Dockerfile reference | Docker Documentation
当查找Dockerfile文件的时候,若是我们不在那个路径当中,我们可以使用"docker run -f /path/tp/a/Dockerfile .",使用绝对路径找到那个Dockerfile。
2、RUN和FROM
FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
- shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
- exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
注意:在shell编程中,若是使用"\"执行命令的时候,不管前边命令执行与否都会执行后边的。"&&"则不是这样的,若是前边命令执行失败,后边的命令就不会执行了。
2.0.1、会增加层数的命令
- RUN
- COPY
- ADD
2.1、set
我们注意到RUN的时候,会出现set这个命令,那么这个命令是用来干什么的呢?
语法:
set [+-abCdefhHklmnpPtuvx]
部分参数说明:
- -e 若指令传回值不等于0,则立即退出shell。
- -u 当执行时使用到未定义过的变量,则显示错误信息。
- -x 执行指令后,会先显示该指令及所下的参数。
[演示]
# -e,若指令传回值不等于0,则立即退出shell。
[root@centos7-docker ~]# set -e
[root@centos7-docker ~]# ls
anaconda-ks.cfg getting-started lianxi
[root@centos7-docker ~]# dfjlsk # 这个命令出错了,就直接退出了shell
-bash: dfjlsk: 未找到命令
Connection closed.
Disconnected from remote host(centos7-docker) at 10:54:59.
Type `help' to learn how to use Xshell prompt.
[C:\~]$
# 所以set -e,就是为了弥补\的机制,即前边的命令执行失败,后边的命令还是会执行。使用了之后,命令执行失败就直接退出shell
# -x,执行指令后,会先显示该指令及所下的参数。
[root@centos7-docker ~]# set -ex
++ printf '\033]0;%s@%s:%s\007' root centos7-docker '~'
[root@centos7-docker ~]# ls
+ ls --color=auto
anaconda-ks.cfg getting-started lianxi
++ printf '\033]0;%s@%s:%s\007' root centos7-docker '~'
# -u,当执行时使用到未定义过的变量,则显示错误信息。
[root@centos7-docker ~]# set -eux
++ printf '\033]0;%s@%s:%s\007' root centos7-docker '~'
[root@centos7-docker ~]# echo $fan
-bash: fan: 为绑定变量
Connection closed.
Disconnected from remote host(centos7-docker) at 11:00:15.
Type `help' to learn how to use Xshell prompt.
[C:\~]$
3、CMD
类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。镜像制作完成,启动容器使用镜像的时候执行的,容器启动后执行的命令。
- RUN 是在 docker build。在制作镜像的过程中执行的,可以RUN很多命令。但是能用一个RUN就用一个RUN,避免增加不必要的层数。
作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
3.1、ENTRYPOINT
类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。
优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
格式1:Theexecform, which is the preferred form,推荐使用的格式
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]
格式2:Theshellform:
ENTRYPOINT command param1 param2
可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
示例:
假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
1、不传参运行
$ docker run nginx:test
容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf
2、传参运行
$ docker run nginx:test -c /etc/nginx/new.conf
容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)
nginx -c /etc/nginx/new.conf
3.2.、ENTRYPONIT和CMD的区别
-
docker run 启动容器的时候,可以传递参数进来给ENTRYPOINT里边的命令
-
当两者都存在的时候,CMD里的内容会变成ENTRYPOINT的参数,例如:
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 3306 33060
CMD ["mysqld"]
# 相当于 "docker-entrypoint.sh mysqld"
3.3、HEALTHCHECK
用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
The options that can appear before CMD are(选项):
- --interval=DURATION(default:30s)
- --timeout-DURATION(default:30s)
- --start-period=DURATION(default:0s)
- --retries-N(default:3)
例子:
# timeout(等待时间为3s);interval(时间距离为5m)
HEALTHCHECK --interval=5m --timeout=3s\
CMD curl -f http://localhost/ || exit 1
# 用"curl -f http://localhost/ || exit 1 " 检查容器是否可以运行。在k8s中,这个叫做探针
4、VOLUME
定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
- 就是将容器里的某个路径挂载到宿主机的卷上
格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点
在Dockerfile中有"VOLUME /myvol"这条命令的时候,这条命令是在容器里执行的。例如:若是在容器中执行了这条命令,那么他就会在宿主机的"/var/lib/docker/volume"文件夹下边自动生成一个与容器绑定(mount)的卷,假如这个卷的名字叫做"abcd"。那么,当我们在容器的/myvol里边新建一个sc.txt文件的时候,对应的也会在宿主机的/var/lib/docker/volume文件下创建一个sc.txt。因为在这里(卷)创建的文件或者文件夹都会保存在宿主机里边。因为卷是实现容器和宿主机数据共享的。
[操作]
Dockerfile文件内容如下:
使用"docker container inspect zhengbo-1"查看这个容器对应的卷是哪个
无论我们在宿主机的卷中还是在容器里的卷中加入任何文件或者文件夹,这些文件或者文件夹都会在宿主机和容器之间共享。
5、ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0 # 将7.2.0赋值给NODE_VERSION
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
5.1、ARG(argument)
构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
格式:
ARG <参数名>[=<默认值>]
[例子]
6、STOPSIGNAL
语法:
STOPSIGNAL signal
[演示阻止信号的例子]
STOPSIGNAL SIGQUIT # 用来阻止信号的
[演示屏蔽信号的例子]
[root@centos7-docker lianxi]# cat for.sh
# 这个是捕捉信号,若是捕捉到1、2、15这三种信号,那么就会输出"I am busy",且捕捉之后原来信号的作用会失效,除了-9强制执杀死信号不能被捕获的
trap "echo I am busy" 1 2 15
for i in {1..100}
do
echo $1
sleep 1
done
7、制作镜像练习
要求:
- 以centos7作为基础镜像
- 在里边安装好ip、vim、ping命令
- 编译好nginx,使用我们指定的配置文件nginx.conf install_nginx.sh
- 启动容器的时候,就启动nginx
- 网页代码上传到容器里
- 直接做到镜像里
- 使用数据卷挂载使用
第一步:准备环境新建目录
[root@centos7-docker ~]# cd /mydocker/
[root@centos7-docker mydocker]# mkdir nginx
[root@centos7-docker mydocker]# cd nginx/
[root@centos7-docker nginx]# pwd
/mydocker/nginx
准备安装nginx的脚本和nginx的源码文件
#!/bin/bash
#解决软件的依赖关系,需要安装的软件包
yum install epel-release -y
yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel gcc gcc-c++ autoconf automake make psmisc net-tools lsof vim geoip geoip-devel wget -y
#下载nginx软件
mkdir /nginx -p
cd /nginx
#wget https://nginx.org/download/nginx-1.21.4.tar.gz
#解压软件
tar xf nginx-1.21.6.tar.gz
#进入解压后的文件夹
cd nginx-1.21.6
#编译前的配置
./configure --prefix=/usr/local/nginx1 --user=lilin --group=lilin --with-http_ssl_module --with-threads --with-http_v2_module --with-http_stub_status_module --with-stream --with-http_geoip_module --with-http_gunzip_module
这个nginx-1.21.6.tar.gz压缩包需要我们自己去nginx官网下载安装:nginx: download 这是下载地址
下载之后我们使用"rz"命令上传到linux里边
[root@centos7-docker nginx]# rz
[root@centos7-docker nginx]# ls
install_nginx.sh nginx-1.21.6.tar.gz
或者我们可以使用这个命令
[root@centos7-docker nginx]# crul -O https://nginx.org/download/nginx-1.21.6.tar.gz
# 这个链接地址,我们只需要打开上面我分享的链接进去之后,选择版本之后,进入到一个新页面,点击压缩包的右键就能复制链接地址了
# 这是大o
第二步:编写Dockerfile
[root@centos7-docker nginx1]# cat Dockerfile
FROM centos:7
ENV NGINX_VERSION 1.21.6
ENV AUTHOR FanMY_71
# 这个不写LABEL也无所谓,就是一个标签
LABEL maintainer="fan<111111@qq.com>"
# 这里若是没有这个目录的话。docker服务应该会给我们新建这个目录,但是为了规范起见,我们还是写上这个新建目录命令
RUN mkdir /nginx
WORKDIR /nginx
COPY . /nginx
1
RUN set -ex ; \
bash install_nginx.sh ; \
yum install vim iputils net-tools iproute -y
EXPOSE 80
# 这个路径的sbin前边要和install_nginx.sh中的编译前配置工作的路径是一样的,prefix=/usr/local/nginx
# 一定要注意!不然会出现错误的!!
ENV PATH=/usr/local/nginx1/sbin:$PATH
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]
第三步:生成镜像
[root@centos7-docker nginx]# ls
Dockerfile install_nginx.sh nginx-1.21.6.tar.gz
[root@centos7-docker nginx]# docker build -t fan-nginx:1.0 .
[root@centos7-docker nginx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
fan-nginx 1.0 340d151ce5e4 3 minutes ago 593MB
第四步:启动容器
第五步:测试访问web服务
curl + IP地址:端口号
或者去浏览器里输入这个地址
我们nginx容器的页面路径是放在/usr/local/bginx1/html里边的。我们使用数据卷实现第五个要求,
容器使用宿主机的里网站数据,所以以后更新就直接修改宿主机里的文件就行
或者创建一个卷,并拷贝宿主机的/web到卷的路径里边
那么我们要是使用镜像解决第五个问题呢?
将网站的数据做到镜像里边去。
拷贝网站代码到镜像里的nginx的网页根目录