DokcerFile 镜像定制
定制docker镜像的方式有两种:
手动修改容器内容,导出新的镜像。
基于dockerfile自行编写指令,基于指令流程创建镜像。
更多k8s技术文档,猛戳这里:kubernetes系列技术文档
Dockerfile简介
镜像是多层存储,每一层都是在前一层的基础上进行修改;容器也是多层存储,以镜像为基础层,在其基础上加一层作为容器运行时的存储层。
刚才说了,创建镜像的两个方法:
手动修改容器内容,然后dokcer commit提交容器为新的镜像
通过在dockerfile中定义一系列的命令和参数构建成的脚本,然后这些命令应用于基础镜像,依次添加层,最终生成一个新的镜像。极大的简化了部署工作。
Dockerfile主要组成部分基础镜像信息 FROM centos:7.9
制作镜像操作指令 RUN yum install -y nginx
容器启动时执行指令 CMD [“/bin/bash”]
宿主机直接部署软件流程与Dockerfile部署软件流程对比
需求 : 安装一个mysql,并启动。
虚拟机部署形式:
1. 开启vmware
2. 运行某一个虚拟即,centos7
3. centos7安装mysql yum install mysql-server
4. 通过脚本或者命令,启动mysql即可
部署缓慢,且修改了宿主机的环境,删除较为麻烦,占用宿主机的一个3306端口容器的部署形式:
1. 开始vmware
2. 运行虚拟机centos7(宿主机)
3. 安装docker容器软件
4. 获取mysql镜像即可,docker pull mysql:tag(你无法自由控制,该mysql的基础镜像时什么发行版本,你获取的镜像,是别人定制好的,你下载使用的默认时Debian发行版,你希望得到一个基于centos7.9的发行版本,运行mysql)
5. 直接运行该镜像,通过端口映射,运行mysql
6. 访问宿主机对的一个映射端口,访问到容器内的mysql想自定义镜像,就得自己写脚本,也就是dockerfile了
Dokcerfile指令
FROM 指定基础镜像MAINTAINER 指定维护者信息,可以没有RUN 你想让它干啥(在命令前面加上RUN即可)ADD 添加宿主机的文件到容器内,还多了一个自动解压的功能# RUN tar -Zxf /opt/xx.tgz # 错!该tgz文件不存在! !COPY 作用和ADD是一样的,都是拷贝宿主机的文件到容器内, COPY就是仅仅拷贝WORKDIR 相当于cd命令,设置当前工作目录VOLUME 设置目录映射,挂载主机目录EXPOSE 指定对外的端口,在容器内暴露一个端口,端口 EXPORT 80CMD 指定容器启动后的要干的事情ENTRYPOINT 作用和CMD一样,都是在指定容器启动程序以及参数。# 当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是把CMD的内容当作参数传递给ENTRYPOINT指令。ARG 设置环境变量# ARG只是用于构建镜像需要设置的变量,容器运行时就消失了ENV 和ARG一样,都是设置环境变量# 区别在于ENV无论是在镜像构建时,还是容器运行,该变量都可以使用USER 用于改变环境,用于切换用户
更多k8s技术文档,猛戳这里:kubernetes系列技术文档
Dokcerfile实践
需求:通过dockerfile,构建nginx镜像,且运行容器后,生成的页面是”辣辣小姐姐”。
1. 创建Dockerfile,注意文件名,必须是这个[root@docker01 ~]# mkdir /learn_docker[root@docker01 ~]# cd /learn_docker/[root@docker01 learn_docker]# vim DockerfileFROM nginxRUN echo "<meta charset=utf-8>辣辣小姐姐" > /usr/share/nginx/html/index.html2. 构建Dockerfile[root@docker01 learn_docker]# docker build .3. 修改镜像名字[root@docker01 learn_docker]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE<none> <none> 950549357c1f 18 seconds ago 133MBnginx latest 08b152afcfae 6 days ago 133MB[root@docker01 learn_docker]# docker tag 950549357c1f my_nginx4. 运行该镜像docker run -d -p 80:80 my_nginx5. 查看宿主机的80端口http://192.168.15.80/# 辣辣小姐姐
Dokcerfile相关指令用法
COPY
copy指令从宿主机复制文件或者目录到新的一层镜像内如:copy nana.py /opt支持多个文件,以及通配符形式的复制,语法要满足Golang的filepath.Matchcopy na* /tmp/cc?.txt /optCOPY指令能够保留源文件的元数据,访问时间等等,这点很重要
ADD
特性和COPY基本一致,不过多了些功能1. 源文件是一个URL,此时dockcer引擎会下载该链接,放入目标路径,且权限自动设为600。若这不是期望结果,还得增加一层RUN指令进行调整# ADD nana.tgz /home# RUN xxx修改命令2. 源文件是一个URL,且是一个压缩包,不会自动解压,也得单独用RUN指令解压3. 源文件是一个压缩文件,且是gzip,bzip,xz,tar情况,ADD指令会自动解压压缩该文件到没有文件
CMD
用法,注意是双引 # CMD在容器内运行某个命令,启动程序# 该镜像在运行容器实例的时候,执行的具体参数是什么CMD["参数1","参数2"]在指定了entrypoint指令后,用CMD指定具体的参数dokcer不是虚拟机,容器就是一个进程,既然是进程,那么程序在启动的时候需要指定些运行参数,这就是CMD指令作用例如centos镜像默认的CMD是/bin/bash,直接docker run -it centos会直接进入bash解释器。也可以启动容器时候,指定参数: docker run -it centos cat /etc/os-releaseCMD ["/bin/bash"]# 该容器运行时,执行的命令# 等同于命令行的直接操作:docker run -it centos cat /etc/os-releaseCMD ["cat","/etc/os-release"]
容器内运行程序
这里要注意的是,docker不是虚拟机的概念,虚拟机的程序运行,基本上都是在后台运行,利用systemctl运行,但是容器内没有后台进程的概念,必须在前台运行。容器就是为了主进程而存在的,主进程如果退出了,容器也就失去意义,自动退出。
例如一个经典的问题:# 这样的写法是错误的,容器会立即退出CMD systemctl start nginx因为systemctl start nginx是以守护进程(默认在后台运行)的形式启动nginx,且CMD命令会转化为CMD ["sh","-c","systemctl start nginx" ]这样的命令主进程是sh解释器,执行完毕后立即结束了,因此容器也就退出了。# 相当于nginx -g daemon off因此正确的做法应该是 CMD ["nginx","-g","daemon off;"]
把宿主机安装,启动nginx的理念放入到dockerfile中1. RUN yum install nginx2. RUN 配置文件修改 sed# RUN systemctl start nginx 容器内的程序必须在前台运行,容器时启动不了的3. 正确的写法应该时CMD ["nginx","-g","daemon off;"]
ENTRYPOINT
dokcer面试题:ENTRYPOINT和CMD的区别以及用法! ! !
ENTRYPOINT作用和CMD一样,都是在指定容器启动程序以及参数。
当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是把CMD的内容当作参数传递给ENTRYPOINT指令。
ENTRYPOINT和CMD的实际用法
实际用法:1. 准备一个Dokcerfile[root@docker01 ~]# cd /learn_docker/[root@docker01 learn_docker]# > Dockerfile [root@docker01 learn_docker]# vim Dockerfile FROM centos:7.8.2003RUN rpm --rebuilddb && yum install epel-release -yRUN rpm --rebuilddb && yum install curl -yCMD ["curl","-s","ip.sb"]# 用法如下dokcer run my_centos curl -s ip.sb # curl -s ip.sb获取本机的公 ip地址2. 构建镜像[root@docker01 learn_docker]# docker build .Sending build context to Docker daemon 2.048kBStep 1/4 : FROM centos:7.8.2003 ---> afb6fca791e0Step 2/4 : RUN rpm --rebuilddb && yum install epel-release -y ---> Using cache ---> 81b4e83fb0a5Step 3/4 : RUN rpm --rebuilddb && yum install curl -y ---> Using cache ---> bd0074c78b6cStep 4/4 : CMD ["curl","-s","ip.sb"] ---> Running in 295418f71093Removing intermediate container 295418f71093 ---> c920b743282aSuccessfully built c920b743282a3. 查看结果(出现Successfully代表镜像构建完成)Step 4/4 : CMD ["curl","-s","ip.sb"] ---> Running in 295418f71093Removing intermediate container 295418f71093 ---> c920b743282aSuccessfully built c920b743282a4. 检查镜像[root@docker01 learn_docker]# docker tag c920b743282a centos_curl [root@docker01 learn_docker]# docker images | grep curlcentos_curl latest c920b743282a 3 minutes ago 471MB5. 运行镜像,生成容器记录,没有前台运行,因此立即挂了[root@docker01 learn_docker]# docker run centos_curl139.227.102.1896. 上述运行正确,但是我想再传入一个参数,该怎么办# 发现是无法直接传入参数的,该形式是覆盖镜像中的cmd# 就好比把docker镜像,当作一个环境,去执行后面的命令[root@docker01 learn_docker]# docker run centos_curl pwd/[root@docker01 learn_docker]# [root@docker01 learn_docker]# docker run centos_curl -Idocker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-I": executable file not found in $PATH: unknown.7. 想要正确的给容器传入一个参数该怎么办希望容器内能够正确完整的运作该命令的执行结果[root@docker01 learn_docker]# curl -s ip.sb -I # 获取http 头信息HTTP/1.1 200 OKDate: Wed, 28 Jul 2021 15:16:18 GMT...8. 解决办法方式一:给容器传入新的完整的命令,让后面的命令覆盖镜像中的cmd# 这是投机取巧的办法,不合适[root@docker01 learn_docker]# docker run centos_curl curl -s ip.sb -IHTTP/1.1 200 OKDate: Wed, 28 Jul 2021 15:18:05 GMTContent-Type: text/plain9. 正确的解决办法[root@docker01 learn_docker]# vim Dockerfile FROM centos:7.8.2003RUN rpm --rebuilddb && yum install epel-release -yRUN rpm --rebuilddb && yum install curl -yENTRYPOINT ["curl","-s","ip.sb"]10. 重新构建镜像# 重新构建镜像速度特别快,并且我们发现镜像的前三个Step的IMAGE ID是一致的,说明前三个的IMAGE ID是直接从缓存中拿的。# 只有Step 4/4的IMAGE ID发生了变化(Dockerfile文件的第四步是更改过的,是重新构建的镜像层),因此更加验证了我们之前所提到的镜像是分层构建的。[root@docker01 learn_docker]# docker build .Sending build context to Docker daemon 2.048kBStep 1/4 : FROM centos:7.8.2003 ---> afb6fca791e0Step 2/4 : RUN rpm --rebuilddb && yum install epel-release -y ---> Using cache ---> 81b4e83fb0a5Step 3/4 : RUN rpm --rebuilddb && yum install curl -y ---> Using cache ---> bd0074c78b6cStep 4/4 : ENTRYPOINT ["curl","-s","ip.sb"] ---> Running in df106e04d533Removing intermediate container df106e04d533 ---> e9479067148cSuccessfully built e9479067148c11. 重新运行该镜像,看结果,以及传入新的参数[root@docker01 learn_docker]# docker tag e9479067148c centos_curl_new# 此时发现,传入的CMD指令,当作了ENTRYPOINT的参数# 其实容器内,执行的完命令是: curl -s ip.sb -I[root@docker01 learn_docker]# docker run centos_curl_new -IHTTP/1.1 200 OKDate: Wed, 28 Jul 2021 15:24:58 GMT...
ARG和ENV指令
设置环境变量
dockerfile脚本,shell脚本ENV NAME="nana"ENV AGE=18ENV MYSQL_VERSION=5.6后续所有的操作,通过$NAMME就可以直接获取变量值使用了,维护dockerfile更加方便ARG和ENV一样,都是设置环境变量ENV无论是在镜像构建时,还是容器运行,该变量都可以使用ARG只是用于构建镜像需要设置的变量,容器运行时就消失了
VOLUME
容器在运行时,应该保证在存储层不写入任何数据,运行在容器内产生的数据,我们推荐是挂载,写入到宿主机上,进行维护。
# mount /mnt VOLUME /data # 将容器内的/data文件夹,在容器运行时,该目录自动挂载为匿名卷,任何向该目录中写入数据的操作,都不会被容器记录,保证的容器存储无状态理念。# Dockerfile[root@docker01 ~]# cd /learn_docker/[root@docker01 learn_docker]# > Dockerfile [root@docker01 learn_docker]# vim Dockerfile FROM centosMAINTAINER nanaVOLUME ["/data1","/data2"]# 该容器运行的时候,这两个目录自动和宿主机的目录做好映射关系docker build .# 运行该镜像docker run 86b4dceba89a# 查看生成的容器信息[root@docker01 nana]# docker ps -a | head -2CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES84014622b3a4 86b4dceba89a "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago sharp_noether# dokcer inspect命令查看[root@docker01 learn_docker]# docker inspect 86b4dceba89a "Volumes": { "/data1": {}, "/data2": {} },1. 容器数据挂载的方式,通过dockerfile,指定VOLUME目录2. 通过docker run -v参数,直接设置需要映射挂载的目录
EXPOSE
指定容器运行时对外提供的端口服务。
帮助使用该镜像的人,快速理解该容器的一个端口业务docker port 容器dokcer run -p 宿主机端口:容器端口docker run -P # 作用是随机 宿主机端口:容器内端口
WORKDIR
用于在dockerfile中,目录的切换,更改工作目录
WORKDIR /opt
USER
用于改变环境,用于切换用户
USER rootUSER nana
使用Dockerfile构建一个 站镜像
传统方式创建一个 站站点
nginx,修改首页内容,html 站就跑起来了。web server,提供web服务,提供代理转发,提供 关,限流等等。。。
web framework。web框架,一般由开发,通过某个开发语言,基于某个web框架,自己去开发一个web站点,python,django框架。
使用Dockerfile创建一个 站站点
用python语言,基于flask web框架,开发一个自己的 站,写一个后端的 站代码
开发dockerfile,部署该代码,生成镜像
其他人基于该镜像,docker run就可以在电脑跑起来你这个 站
使用docker的优势
比如安装一个etcd、naco,都是一些比较复杂的软件。
需要依赖于go语言环境,比如需要依赖于java环境,在自己的机器安装好对应的开发环境,以及对应的版本,以及各种依赖。。。
tomcat 依赖于jdk环境
当你有了docker,
docker pull tomcat # 这些主流的镜像都可以直接找到,并且该镜像中,就已经打包好了java环境
docker run tomcat xxx … # 直接可以访问tomcat了
1. 在宿主机下,准备一个目录,准备好dockerfile,代码文件# 写一个flask的python代码# 创建代码文件[root@docker01 ~]# cd /learn_docker/[root@docker01 ~]# vim nana_flask.py #coding:utf8from flask import Flaskapp=Flask(__name__)# @app.route(装饰器), 站的route,指的是url地址后面的文件路径@app.route("/nana")def nana(): return "From Docker,nana是只臭猪猪!!!"if __name__=="__main__": app.run(host="0.0.0.0",port=8080)2. 编写Dockerfile[root@docker01 learn_docker]# vim DockerfileFROM centos:7.8.2003RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo;RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo;RUN yum makecache fast;RUN yum install python3-devel python3-pip -yRUN pip3 install -i https://pypi.douban.com/simple flaskCOPY nana_flask.py /optWORKDIR /optEXPOSE 8080CMD ["python3","nana_flask.py"]3. 构建镜像# --no-cache不是使用之前旧的缓存,重新构建镜像[r
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!