K8S系列第四篇(Dockerfile)
DokcerFile 镜像定制
更多精彩内容请关注:
定制docker镜像的⽅式有两种:
1. ⼿动修改容器内容,导出新的镜像。
2. 基于dockerfile⾃⾏编写指令,基于指令流程创建镜像。
Dockerfile简介
镜像是多层存储,每⼀层都是在前⼀层的基础上进⾏修改;
容器也是多层存储,以镜像为基础层,在其基础上加⼀层作为容器运⾏时的存储层。
刚才说了,创建镜像的两个⽅法:
1. ⼿动修改容器内容,然后dokcer commit提交容器为新的镜像
2. 通过在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 / # 报错!该tgz⽂件不存在! !
COPY 作⽤和ADD是⼀样的,都是拷贝宿主机的⽂件到容器内, COPY就是仅仅拷贝
WORKDIR 相当于cd命令,设置当前⼯作⽬录
VOLUME 设置⽬录映射,挂载主机⽬录
EXPOSE 指定对外的端⼝,在容器内暴露⼀个端⼝,端⼝ EXPORT 80
CMD 指定容器启动后的要⼲的事情
ENTRYPOINT 作⽤和CMD⼀样,都是在指定容器启动程序以及参数。
# 当指定了ENTRYPOINT之后,CMD指令的语义就有了变化,⽽是把CMD的内容当作参数传递给ENTRYPOINT指令。
ARG 设置环境变量
# ARG只是⽤于构建镜像需要设置的变量,容器运⾏时就消失了
ENV 和ARG⼀样,都是设置环境变量
# 区别在于ENV⽆论是在镜像构建时,还是容器运⾏,该变量都可以使⽤
USER ⽤于改变环境,⽤于切换⽤户
Dokcerfile实践
需求:通过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端⼝
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指令进⾏调整
# /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
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: :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
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
使⽤Dockerfile构建⼀个⽹站镜像
传统⽅式创建⼀个⽹站站点
1. nginx,修改⾸页内容,html⽹站就跑起来了。web server,提供web服务,提供代理转发,提供⽹关,限流等等。。。
2. web framework。web框架,⼀般由开发,通过某个开发语⾔,基于某个web框架,⾃⼰去开发⼀个web站点,python,django框架。
使⽤Dockerfile创建⼀个⽹站站点
1. ⽤python语⾔,基于flask web框架,开发⼀个⾃⼰的⽹站,写⼀个后端的⽹站代码
2. 开发dockerfile,部署该代码,⽣成镜像
3. 其他⼈基于该镜像,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__)
# @ute(装饰器),⽹站的route,指的是url地址后⾯的⽂件路径
@ute("/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 /pos.po mirrors.aliyun/po;
RUN curl -o /pos.po mirrors.aliyun/po;
RUN yum makecache fast;
RUN yum install python3-devel python3-pip -y
RUN pip3 install -i pypi.douban/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⽹站
浏览器输⼊: 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__)
# @ute(装饰器),⽹站的route,指的是url地址后⾯的⽂件路径
@ute("/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⽹站
浏览器输⼊: 192.168.15.80:90/nana
# From Docker,nana是只臭猪猪ABC
更多精彩内容请关注:
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 ~]# 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
浏览器访问:192.168.15.80:8000/ ==> 可以访问到nginx
# 查看容器内⽇志,实时刷新
docker logs -f
# 查看运⾏时,以及挂掉的容器记录
docker ps 在运⾏的容器
dokcer ps -a 挂掉以及活着的容器
# 停⽌启动
docker start
centos7没有vim命令docker stop
# 进⼊容器内
docker exec -it 容器id bash
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论