DokcerFile 镜像定制
更多精彩内容请关注微信公众号:新猿技术生态圈
定制docker镜像的方式有两种:
-
手动修改容器内容,导出新的镜像。 -
基于dockerfile自行编写指令,基于指令流程创建镜像。
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 添加宿主机的文件到容器内,还多了一个自动解压的功能
COPY 作用和ADD是一样的,都是拷贝宿主机的文件到容器内, COPY就是仅仅拷贝
WORKDIR 相当于cd命令,设置当前工作目录
VOLUME 设置目录映射,挂载主机目录
EXPOSE 指定对外的端口,在容器内暴露一个端口,端口 EXPORT 80
CMD 指定容器启动后的要干的事情
ENTRYPOINT 作用和CMD一样,都是在指定容器启动程序以及参数。
ARG 设置环境变量
ENV 和ARG一样,都是设置环境变量
USER 用于改变环境,用于切换用户
Dokcerfile实践
需求:通过dockerfile,构建nginx镜像,且运行容器后,生成的页面是"辣辣小姐姐"。
1. 创建Dockerfile,注意文件名,必须是这个
[root@docker01 ~]
[root@docker01 ~]
[root@docker01 learn_docker]
FROM nginx
RUN echo "<meta charset=utf-8>辣辣小姐姐" > /usr/share/nginx/html/index.html
2. 构建Dockerfile
[root@docker01 learn_docker]
3. 修改镜像名字
[root@docker01 learn_docker]
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 950549357c1f 18 seconds ago 133MB
nginx latest 08b152afcfae 6 days ago 133MB
[root@docker01 learn_docker]
4. 运行该镜像
docker run -d -p 80:80 my_nginx
5. 查看宿主机的80端口
http://192.168.15.80/
更多精彩内容请关注微信公众号:新猿技术生态圈
Dokcerfile相关指令用法
COPY
copy指令从宿主机复制文件或者目录到新的一层镜像内
如:
copy nana.py /opt
支持多个文件,以及通配符形式的复制,语法要满足Golang的filepath.Match
copy na* /tmp/cc?.txt /opt
COPY指令能够保留源文件的元数据,访问时间等等,这点很重要
ADD
特性和COPY基本一致,不过多了些功能
1. 源文件是一个URL,此时dockcer引擎会下载该链接,放入目标路径,且权限自动设为600。若这不是期望结果,还得增加一层RUN指令进行调整
2. 源文件是一个URL,且是一个压缩包,不会自动解压,也得单独用RUN指令解压
3. 源文件是一个压缩文件,且是gzip,bzip,xz,tar情况,ADD指令会自动解压压缩该文件到没有文件
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"]
CMD ["cat","/etc/os-release"]
容器内运行程序
这里要注意的是,docker不是虚拟机的概念,虚拟机的程序运行,基本上都是在后台运行,利用systemctl运行,但是容器内没有后台进程的概念,必须在前台运行。 容器就是为了主进程而存在的,主进程如果退出了,容器也就失去意义,自动退出。
例如一个经典的问题:
CMD systemctl start nginx
因为systemctl start nginx是以守护进程(默认在后台运行)的形式启动nginx,且CMD命令会转化为
CMD ["sh","-c","systemctl start nginx" ]
这样的命令主进程是sh解释器,执行完毕后立即结束了,因此容器也就退出了。
因此正确的做法应该是 CMD ["nginx","-g","daemon off;"]
把宿主机安装,启动nginx的理念放入到dockerfile中
1. RUN yum install nginx
2. RUN 配置文件修改 sed
3. 正确的写法应该时CMD ["nginx","-g","daemon off;"]
ENTRYPOINT
dokcer面试题: ENTRYPOINT和CMD的区别以及用法! ! !
ENTRYPOINT作用和CMD一样,都是在指定容器启动程序以及参数。
当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,而是把CMD的内容当作参数传递给ENTRYPOINT指令。
ENTRYPOINT和CMD的实际用法
实际用法:
1. 准备一个Dokcerfile
[root@docker01 ~]
[root@docker01 learn_docker]
[root@docker01 learn_docker]
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
2. 构建镜像
[root@docker01 learn_docker]
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]
[root@docker01 learn_docker]
centos_curl latest c920b743282a 3 minutes ago 471MB
5. 运行镜像,生成容器记录,没有前台运行,因此立即挂了
[root@docker01 learn_docker]
139.227.102.189
6. 上述运行正确,但是我想再传入一个参数,该怎么办
[root@docker01 learn_docker]
/
[root@docker01 learn_docker]
[root@docker01 learn_docker]
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]
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:16:18 GMT
...
8. 解决办法
方式一:给容器传入新的完整的命令,让后面的命令覆盖镜像中的cmd
[root@docker01 learn_docker]
HTTP/1.1 200 OK
Date: Wed, 28 Jul 2021 15:18:05 GMT
Content-Type: text/plain
9. 正确的解决办法
[root@docker01 learn_docker]
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. 重新构建镜像
[root@docker01 learn_docker]
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]
[root@docker01 learn_docker]
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
容器在运行时,应该保证在存储层不写入任何数据,运行在容器内产生的数据,我们推荐是挂载,写入到宿主机上,进行维护。
VOLUME /data
[root@docker01 ~]
[root@docker01 learn_docker]
[root@docker01 learn_docker]
FROM centos
MAINTAINER nana
VOLUME ["/data1","/data2"]
docker build .
docker run 86b4dceba89a
[root@docker01 nana]
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
84014622b3a4 86b4dceba89a "/bin/bash" 2 minutes ago Exited (0) 2 minutes ago sharp_noether
[root@docker01 learn_docker]
"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
使用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,代码文件
[root@docker01 ~]
[root@docker01 ~]
from flask import Flask
app=Flask(__name__)
@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]
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. 构建镜像
[root@docker01 learn_docker]
...
Successfully built 9e731f439e41
Successfully tagged nana_flask:latest
4. 查看构建好的镜像
[root@docker01 learn_docker]
REPOSITORY TAG IMAGE ID CREATED SIZE
nana_flask latest 9e731f439e41 3 minutes ago 649MB
5. 运行镜像,生成容器
[root@docker01 learn_docker]
d9f2f83d16bdd0364473d6e4043c433cbd8e3286e87ecbf93fb3fd5e08ac8002
[root@docker01 learn_docker]
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
如何修改容器内的网站的内容
方法一:修改宿主机的代码,以及dockerfile,重新构建镜像
[root@docker01 ~]
...
def nana():
return "From Docker,nana是只臭猪猪!!!"
...
方法二:你可以经入到已经运行的容器内,修改代码,重启容器即可
1. 进入容器内部
[root@docker01 learn_docker]
[root@d9f2f83d16bd opt]
nana_flask.py
2. 修改容器内的代码
[root@d9f2f83d16bd opt]
from flask import Flask
app=Flask(__name__)
@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
[root@docker01 learn_docker]
d9f2f83d16bd
[root@docker01 learn_docker]
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
更多精彩内容请关注微信公众号:新猿技术生态圈
Docker基础复习
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 ~]
root@7478064e9fff:/
[root@docker01 ~]
79d7fcfdc60f2c40e6d92790be6ad6f3bf9db49fda0e46cadb196be6677b4f73
[root@docker01 ~]
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
docker inspect --format '{{ .NetworkSettings.IPAddress }}' 容器id
dokcer run启动容器的时候,dokcer后台操作流程是
- 检查本地是否有该镜像,没有就下载
- 利用镜像创建且启动一个容器
- 分配容器文件系统,在只读的镜像层挂载读写层
- 宿主机的网桥接口会分配一个虚拟接口到容器中
- 容器获得地址池的ip地址
- 执行用户指定的程序
- 若程序里没有进程在运行,容器执行完毕后立即终止
更多精彩内容请关注微信公众号:新猿技术生态圈 更多精彩内容请关注微信公众号:新猿技术生态圈 更多精彩内容请关注微信公众号:新猿技术生态圈
|