docker 常见操作(下)
太久了,甚至一度以为自己已经上传了另一部分内容,哈哈哈。今天更新下。发现直接从 Typora 复制过来我的代码部分和图片都没了,一条条粘贴上去了,如果有错误,先说声抱歉,欢迎评论告诉我,谢谢
docker 镜像
镜像是可以执行的独立轻量软件包,可以用于打包软件运行环境和对应开发的软件,包括了代码,库,环境变量等等。
docker 镜像的基础是 Union 文件系统,支持对文件系统的下去该作为一次提交来叠加,将不同目录挂载到同一个虚拟文件系统下,所以外部看上去只能看到一个文件系统,实际上一次同事加载了多个文件系统。
这样的号出就是共享,例如有多个镜像从相同的 base 镜像构建而来,那么宿主机只需要在存一份 base 镜像即可。镜像的每一层都可以被共用。
容器启动的时候新的可写层被加载到镜像的顶部,被称作容器层,下面的层被称作镜像层,docker 的镜像都是只读的。
打包镜像
- 运行从 docker hub 上下载的镜像:
docker run -it -p 8080:8080 tomcat
- 访问最新版 tomcat 首页可以看到会提示 404:
因为文件都处于 webapps.dist 中而不是默认的 webapps 中。
-
使用
docker exec -it 636c0b8b498a /bin/bash
重新进入到 tomcat 对应的容器中,使用cp -r webapps.dist/* webapps
复制 webapps.dist 中的文件到 webapps 中 -
刷新浏览器就能看到正常的 tomcat 首页了
image-20200304135623974.png
- 以修改过的容器为模板生成一个新的镜像,并命名为 iot/tomcat
docker commit -a="iot" -m="move webapps.dist to webapps" 636c0b8b498a iot/tomcat:8.5.51
- 查看现有镜像可以看到一个为 iot/tomcat 的镜像,然后运行他:
docker run -it -p 8081:8080 iot/tomcat:8.5.51
访问 8081 端口,正常访问
docker 数据卷
docker 容器中产生的数据如果不通过 commit 生成新的镜像,使得数据成为镜像的一部分,那么当容器删除以后数据就消失了。为了保存数据,可以使用数据卷的方式。数据卷使得 docker 做到荣期间继承和共享数据。
命令添加方式
运行容器时添加 -v 参数可以指定数据卷:
docker run -it -v /宿主机绝对路径:/容器内目录 镜像名
运行后会自动创建目录,也可以选择已有目录进行挂载。挂载后可以通过docker inspect 容器ID
的方式进行查看,如下:
通过 dockerfile 添加
在dockerfile 中添加目录
在/mydocker
中新建文件 Dockerfile 文件
在 dockerfile 中添加
VOLUME ["/dataContainer","/dataContainer2","/dataContainer3"]
表示容器内的 "/dataContainer","/dataContainer2","/dataContainer3" 与宿主机绑定。最简单的 dockerfile 可以是:
# volume test
FROM centos
VOLUME ["/dataContainer","/dataContainer2","/dataContainer3"]
CMD echo "Hello world!!!"
CMD /bin/bash
由于考虑到 dockerfile 的移植性考虑,不能使用类似-v /宿主机绝对路径:容器路径
的方式在 dockerfile 中实现
build 生成镜像
通过
docker build -f /mydocker/Dockerfile -t iot/centos .
生成新的镜像,注意最后有个点。然后运行他:
docker run -it iot/centos /bin/bash
值得注意的是:在 Dockerfile 中使用 VOLUME 指令之后的代码,如果尝试对这个数据卷进行修改,这些修改都不会生效!
权限
容器向挂载的目录写入文件或者增加目录以后,主机上可能会遇到没有访问权限的问题,因为 docker 内部默认使用的是 root 用户。例如使用如下命令创建一个容器,同时挂载当前目录到容器内,并再容器内创建文件 tmp.txt
docker run -rm -v "$PWD":/project centos bash -c "touch /project/tmp.txt"
查看 tmp.txt 的文件信息:
image-20200305100505569.png权限、用户,组都是 root,其他用户只能 read,切换其他用户尝试向里面写入东西:
image-20200305100947924.png命令添加 user 参数方式
docker 提供了 --user 参数,可以指定用户名或者 UID,修改命令如下:
docker run --rm --user=$UID:$(id -g $USER) -v "$PWD":/project centos bash -c "touch /project/tmp.txt"
执行后发现已经可以正常在里面写入东西了:
image-20200305105534948.png但是使用 user 参数会有两个缺陷:
-
指定的用户不存在于容器内的
/etc/passwd
中,shell 无法显示用户名。 -
user
参数会指定容器运行时刻的用户和主机一致,因此持有主机挂载的用户目录,但容器内非挂载的目录均无权限。
为了解决这个问题可以编写一个 docker-entrypoint.sh 脚本作为 Dockerfile 的 ENTRYPOINT,在脚本中创建一个和宿主机上相同 UID 的用户,并用用 gosu 切换到还用户执行命令,UID 需要在 docker run
阶段通过参数传入
如果是希望容器只能访问宿主机上的目录,则可以在容器内路径后面加上 ro,如下:
docker run -it -v /datahost/:/datacontainer:ro centos
数据卷容器
命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器。
- 以
iot/centos
为模板,分别启动三个容器,container1,container2,container3。container2 、container3 均继承自 container1。如下:
这三个容器都拥有容器卷 dataVolumeContainer0
、dataVolumeContainer1
。可以通过docker inspect
看到他们指向宿主机上的同一个目录。
- 分别在 container2 与 container3 中新增文件:
可以看到 container3 新增的文件在 container2 中同样能看到。
回到 container1,子容器中添加的内容在父容器中同样可以看到。
image-20200305145513404.png-
在父容器中删除 c2_add.txt 同时在 c3_add.txt 中添加 "c1 hello world"。
image-20200305151119932.png
-
回到 container2 中查看,并且修改 c1_add.txt 与 c3_add.txt:
image-20200305151414993.png
-
回到 container3 中查看:
image-20200305151531320.png -
现在删除 container1 ,然后查看 container 修改 c1_add.txt ,在 container3 中是否可以访问:
可见即使父容器被删除了,其新建的文件其他子容器仍然能修改,读取。
-
新建容器 container4 ,继承自 container3,然后删除 container2 和 container3,查看在 container4 中是否还能查看之前的文件
image-20200305154418348.png
可知:容器之间配置信息可以互相传递,数据卷的生命周期一直持续到没有容器使用它为止。
dockerfile
dockerfile 是用来构建 docker 镜像的文件。
-
dockerfile 要求每条保留字指令必须为大写字母且后面要跟至少一个参数
-
指令从上到下执行
-
用于添加注释
-
每条指令都会创造一个新的镜像层(临时),并对镜像进行提交
dockerfile 构建流程
-
docker 从基础镜像运行一个容器
-
执行一条指令并对容器做出修改
-
执行类似
docker commit
的操作并且提交一个新的镜像层 -
docker 再鲸鱼刚提交的镜像层运行一个新的的容器
-
执行 dockerfile 中下一条指令知道所有指令都执行完成
dockerfile 关键字
关键字 | 含义 |
---|---|
FROM | 基础镜像,表示新镜像是基于那个镜像的 |
MAINTAINER | 镜像维护者的姓名和邮箱地址 |
RUN | 容器构建是需要运行的命令 |
EXPOSE | 当前容器对外暴露的端口 |
WORKDIR | 创建容器后终端登录的默认路径 |
ENV | 用来构建镜像过程中设置环境变量 |
ADD | 将宿主机目录下的文件拷贝进镜像且 ADD 命令会自动处理 URL 与解压 tar 压缩包 |
COPY | 类似 ADD |
VOLUME | 容器数据卷 |
CMD | 指定容器启动时要运行的命令 |
ENTRYPOINT | 指定容器启动时要运行的命令 |
ONBUILD | 当构建一个被继承的 dockerfile 时运行的命令,父镜像被子继承后父镜像的 ONBUILD 被触发 |
备注:
- ENV 设置环境变量以后再后续的指令中可以直接使用,例如:
ENV TEST /usr/test
WORKDIR $TEST
WORKDIR $TEST</pre>
-
COPY 拷贝有两种形式,
COPY src dest
或者COPY ["src","dest"]
-
ENTRYPOINT 在 docker run 镜像之后的参数会被当作参数传递给 ENTRYPOINT
-
CMD 也有两种形式
shell 格式:
CMD <命令>
exec 格式:
CMD ["可执行文件", "参数1", "参数2"]
参数列表格式:类似 exec 格式,
CMD ["参数1", "参数2"...]
但是不传入可执行文件,可以用在ENTRYPOINT
指令之后,用于指定参数
编写 dockerfile 文件
FROM centos
MAINTAINER djz<jinzhuang.dong@unilever-le.com>
# 把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
# 把 test.tar.gz 添加到容器中
ADD test.tar.gz /usr/local/
# 安装vim编辑器
RUN yum -y install vim
# 设置工作访问时候的WORKDIR路径,登录目录
ENV WORKSPACE /usr/local
WORKDIR $WORKSPACE
# 容器运行时监听的端口
EXPOSE 80
CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
保存然后运行:
docker build -f Dockerfile -t iotvim/centos:7.1 .
即可生成镜像,然按照正常镜像运行方式即可运行
docker run -it iotvim/centos:7.1
会发现默认处在 /usr/local
下,且可以使用 vim