更多精彩内容请关注微信公众号:新猿技术生态圈html
定制docker镜像的方式有两种:java
手动修改容器内容,导出新的镜像。python
基于dockerfile自行编写指令,基于指令流程建立镜像。mysql
镜像是多层存储,每一层都是在前一层的基础上进行修改;
容器也是多层存储,以镜像为基础层,在其基础上加一层做为容器运行时的存储层。
刚才说了,建立镜像的两个方法:linux
手动修改容器内容,而后dokcer commit提交容器为新的镜像nginx
经过在dockerfile中定义一系列的命令和参数构建成的脚本,而后这些命令应用于基础镜像,依次添加层,最终生成一个新的镜像。极大的简化了部署工做。web
Dockerfile主要组成部分
基础镜像信息 FROM centos:7.9 制做镜像操做指令 RUN yum install -y nginx 容器启动时执行指令 CMD ["/bin/bash"]
宿主机直接部署软件流程与Dockerfile部署软件流程对比
需求 : 安装一个mysql,并启动。面试
虚拟机部署形式:sql
1. 开启vmware 2. 运行某一个虚拟即,centos7 3. centos7安装mysql yum install mysql-server 4. 经过脚本或者命令,启动mysql便可 部署缓慢,且修改了宿主机的环境,删除较为麻烦,占用宿主机的一个3306端口容器的部署形式:docker
1. 开始vmware 2. 运行虚拟机centos7(宿主机) 3. 安装docker容器软件 4. 获取mysql镜像便可,docker pull mysql:tag(你没法自由控制,该mysql的基础镜像时什么发行版本,你获取的镜像,是别人定制好的,你下载使用的默认时Debian发行版,你但愿获得一个基于centos7.9的发行版本,运行mysql) 5. 直接运行该镜像,经过端口映射,运行mysql 6. 访问宿主机对的一个映射端口,访问到容器内的mysql想自定义镜像,就得本身写脚本,也就是dockerfile了
FROM 指定基础镜像 MAINTAINER 指定维护者信息,能够没有 RUN 你想让它干啥(在命令前面加上RUN便可) ADD 添加宿主机的文件到容器内,还多了一个自动解压的功能 # RUN tar -Zxf /opt/xx.tgz # 报错!该tgz文件不存在! ! COPY 做用和ADD是同样的,都是拷贝宿主机的文件到容器内, COPY就是仅仅拷贝 WORKDIR 至关于cd命令,设置当前工做目录 VOLUME 设置目录映射,挂载主机目录 EXPOSE 指定对外的端口,在容器内暴露一个端口,端口 EXPORT 80 CMD 指定容器启动后的要干的事情 ENTRYPOINT 做用和CMD同样,都是在指定容器启动程序以及参数。 # 当指定了ENTRYPOINT以后,CMD指令的语义就有了变化,而是把CMD的内容看成参数传递给ENTRYPOINT指令。 ARG 设置环境变量 # ARG只是用于构建镜像须要设置的变量,容器运行时就消失了 ENV 和ARG同样,都是设置环境变量 # 区别在于ENV不管是在镜像构建时,仍是容器运行,该变量均可以使用 USER 用于改变环境,用于切换用户
需求:经过dockerfile,构建nginx镜像,且运行容器后,生成的页面是"辣辣小姐姐"。
1. 建立Dockerfile,注意文件名,必须是这个 [root@docker01 ~]# mkdir /learn_docker [root@docker01 ~]# cd /learn_docker/ [root@docker01 learn_docker]# vim Dockerfile FROM nginx RUN echo "<meta charset=utf-8>辣辣小姐姐" > /usr/share/nginx/html/index.html 2. 构建Dockerfile [root@docker01 learn_docker]# docker build . 3. 修改镜像名字 [root@docker01 learn_docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 950549357c1f 18 seconds ago 133MB nginx latest 08b152afcfae 6 days ago 133MB [root@docker01 learn_docker]# docker tag 950549357c1f my_nginx 4. 运行该镜像 docker run -d -p 80:80 my_nginx 5. 查看宿主机的80端口 http://192.168.15.80/ # 辣辣小姐姐
更多精彩内容请关注微信公众号:新猿技术生态圈
COPY
copy指令从宿主机复制文件或者目录到新的一层镜像内 如: copy nana.py /opt 支持多个文件,以及通配符形式的复制,语法要知足Golang的filepath.Match copy na* /tmp/cc?.txt /opt COPY指令可以保留源文件的元数据,访问时间等等,这点很重要
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-release CMD ["/bin/bash"] # 该容器运行时,执行的命令 # 等同于命令行的直接操做:docker run -it centos cat /etc/os-release CMD ["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 nginx 2. 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.2003 RUN rpm --rebuilddb && yum install epel-release -y RUN rpm --rebuilddb && yum install curl -y CMD ["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.048kB Step 1/4 : FROM centos:7.8.2003 ---> afb6fca791e0 Step 2/4 : RUN rpm --rebuilddb && yum install epel-release -y ---> Using cache ---> 81b4e83fb0a5 Step 3/4 : RUN rpm --rebuilddb && yum install curl -y ---> Using cache ---> bd0074c78b6c Step 4/4 : CMD ["curl","-s","ip.sb"] ---> Running in 295418f71093 Removing intermediate container 295418f71093 ---> c920b743282a Successfully built c920b743282a 3. 查看结果(出现Successfully表明镜像构建完成) Step 4/4 : CMD ["curl","-s","ip.sb"] ---> Running in 295418f71093 Removing intermediate container 295418f71093 ---> c920b743282a Successfully built c920b743282a 4. 检查镜像 [root@docker01 learn_docker]# docker tag c920b743282a centos_curl [root@docker01 learn_docker]# docker images | grep curl centos_curl latest c920b743282a 3 minutes ago 471MB 5. 运行镜像,生成容器记录,没有前台运行,所以当即挂了 [root@docker01 learn_docker]# docker run centos_curl 139.227.102.189 6. 上述运行正确,可是我想再传入一个参数,该怎么办 # 发现是没法直接传入参数的,该形式是覆盖镜像中的cmd # 就比如把docker镜像,看成一个环境,去执行后面的命令 [root@docker01 learn_docker]# docker run centos_curl pwd / [root@docker01 learn_docker]# [root@docker01 learn_docker]# docker run centos_curl -I docker: 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 OK Date: Wed, 28 Jul 2021 15:16:18 GMT ... 8. 解决办法 方式一:给容器传入新的完整的命令,让后面的命令覆盖镜像中的cmd # 这是投机取巧的办法,不合适 [root@docker01 learn_docker]# docker run centos_curl curl -s ip.sb -I HTTP/1.1 200 OK Date: Wed, 28 Jul 2021 15:18:05 GMT Content-Type: text/plain 9. 正确的解决办法 [root@docker01 learn_docker]# vim Dockerfile FROM centos:7.8.2003 RUN rpm --rebuilddb && yum install epel-release -y RUN rpm --rebuilddb && yum install curl -y ENTRYPOINT ["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.048kB Step 1/4 : FROM centos:7.8.2003 ---> afb6fca791e0 Step 2/4 : RUN rpm --rebuilddb && yum install epel-release -y ---> Using cache ---> 81b4e83fb0a5 Step 3/4 : RUN rpm --rebuilddb && yum install curl -y ---> Using cache ---> bd0074c78b6c Step 4/4 : ENTRYPOINT ["curl","-s","ip.sb"] ---> Running in df106e04d533 Removing intermediate container df106e04d533 ---> e9479067148c Successfully built e9479067148c 11. 从新运行该镜像,看结果,以及传入新的参数 [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 -I HTTP/1.1 200 OK Date: Wed, 28 Jul 2021 15:24:58 GMT ...
ARG和ENV指令
设置环境变量
dockerfile脚本,shell脚本 ENV NAME="nana" ENV AGE=18 ENV 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 centos MAINTAINER nana VOLUME ["/data1","/data2"] # 该容器运行的时候,这两个目录自动和宿主机的目录作好映射关系 docker build . # 运行该镜像 docker run 86b4dceba89a # 查看生成的容器信息 [root@docker01 nana]# docker ps -a | head -2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 84014622b3a4 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 root USER nana
传统方式建立一个网站站点
- 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:utf8 from flask import Flask app=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 Dockerfile FROM centos:7.8.2003 RUN 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 -y RUN pip3 install -i https://pypi.douban.com/simple flask COPY nana_flask.py /opt WORKDIR /opt EXPOSE 8080 CMD ["python3","nana_flask.py"] 3. 构建镜像 # --no-cache不是使用以前旧的缓存,从新构建镜像 [root@docker01 learn_docker]# docker build --no-cache -t "nana_flask" . ... Successfully built 9e731f439e41 Successfully tagged nana_flask:latest 4. 查看构建好的镜像 [root@docker01 learn_docker]# docker images | head -2 REPOSITORY TAG IMAGE ID CREATED SIZE nana_flask latest 9e731f439e41 3 minutes ago 649MB 5. 运行镜像,生成容器 [root@docker01 learn_docker]# docker run -d --name nana_flask_web01 -p 90:8080 nana_flask d9f2f83d16bdd0364473d6e4043c433cbd8e3286e87ecbf93fb3fd5e08ac8002 [root@docker01 learn_docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d9f2f83d16bd nana_flask "python3 nana_flask.…" 2 minutes ago Up 2 minutes 0.0.0.0:90->8080/tcp, :::90->8080/tcp nana_flask_web01 6. 访问宿主主机,查看容器内的flask web网站 浏览器输入: http://192.168.15.80:90/nana # From Docker,nana是只臭猪猪!!!
如何修改容器内的网站的内容
方法一:修改宿主机的代码,以及dockerfile,从新构建镜像
[root@docker01 ~]# vim nana_flask.py ... def nana(): return "From Docker,nana是只臭猪猪!!!" # 修改return值,从新生成镜像 ...
方法二:你能够经入到已经运行的容器内,修改代码,重启容器便可
1. 进入容器内部 [root@docker01 learn_docker]# docker exec -it d9f2f83d16bd bash [root@d9f2f83d16bd opt]# ls nana_flask.py 2. 修改容器内的代码 [root@d9f2f83d16bd opt]# vi nana_flask.py #coding:utf8 from flask import Flask app=Flask(__name__) # @app.route(装饰器),网站的route,指的是url地址后面的文件路径 @app.route("/nana") def nana(): return "From Docker,nana是只臭猪猪!!!ABC!!!" if __name__=="__main__": app.run(host="0.0.0.0",port=8080) 3. 退出容器并重启容器 [root@d9f2f83d16bd opt]# exit exit [root@docker01 learn_docker]# docker restart d9f2f83d16bd d9f2f83d16bd [root@docker01 learn_docker]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d9f2f83d16bd nana_flask "python3 nana_flask.…" 4 minutes ago Up About a minute 0.0.0.0:90->8080/tcp, :::90->8080/tcp nana_flask_web01 4. 访问宿主主机,查看容器内的flask web网站 浏览器输入: http://192.168.15.80:90/nana # From Docker,nana是只臭猪猪!!!ABC!!!
更多精彩内容请关注微信公众号:新猿技术生态圈
Docker容器文件系统
容器是docker的一个核心概念,容器使用一个或者一组应用,他的运行状态以下:
docker利用容器运行应用程序
容器是镜像的运行实例,能够被run、start、stop、rm
每一个容器都是互相隔离,保证平台暗转
容器能够看做是一个简易版Linux环境(没有Linux内核,有root权限、进程、用户空间、网络)
镜像是只读的,容器在启动的时候建立一层可写层
dokcerfile面向开发,docker image(镜像)做为交付标准,docker container(容器)涉及部署和运维,三者合起来完成docker体系。FROM ubuntu:14.04 选择基础镜像 ADD run.sh 添加文件镜像,这一层镜像只有一个内容,就是这个文件 VOLUME /data 设定存储目录,并未添加文件,只是更新了镜像的json文件,便于启动时候读取该层信息 CMD ["./run.sh"] 更新json文件,设定程序入口
docker容器管理总结
# 运行镜像,且进入容器内 [root@docker01 ~]# docker run -it ubuntu bash root@7478064e9fff:/# # 容器运行web程序 # 注意端口使用,数字大一点,建议8000之后开始使用 # --restart=always容器在后台挂掉后,默认重启容器 [root@docker01 ~]# docker run --name my_nginx -d --restart=always -p 8000:80 nginx 79d7fcfdc60f2c40e6d92790be6ad6f3bf9db49fda0e46cadb196be6677b4f73 [root@docker01 ~]# docker ps | head -2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 79d7fcfdc60f nginx "/docker-entrypoint.…" 40 seconds ago Up 39 seconds 0.0.0.0:8000->80/tcp, :::8000->80/tcp my_nginx 浏览器访问:http://192.168.15.80:8000/ ==> 能够访问到nginx # 查看容器内日志,实时刷新 docker logs -f # 查看运行时,以及挂掉的容器记录 docker ps 在运行的容器 dokcer ps -a 挂掉以及活着的容器 # 中止启动 docker start docker stop # 进入容器内 docker exec -it 容器id bash # 删除容器 docker rm 容器id docker rm `docker ps -qa` # 强制杀死并删除容器 docker rm -f 容器id # 查看容器进程资源信息 docker top 容器id # 查看容器内资源 docker stats 容器id # 查看容器具体信息 docker inspect 容器id # 获取容器内的ip地址,容器的格式化参数 docker inspect --format '{{ .NetworkSettings.IPAddress }}' 容器id
dokcer run启动容器的时候,dokcer后台操做流程是
- 检查本地是否有该镜像,没有就下载
- 利用镜像建立且启动一个容器
- 分配容器文件系统,在只读的镜像层挂载读写层
- 宿主机的网桥接口会分配一个虚拟接口到容器中
- 容器得到地址池的ip地址
- 执行用户指定的程序
- 若程序里没有进程在运行,容器执行完毕后当即终止
更多精彩内容请关注微信公众号:新猿技术生态圈
更多精彩内容请关注微信公众号:新猿技术生态圈
更多精彩内容请关注微信公众号:新猿技术生态圈