十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
《深入剖析Kubernetes - 08 | 白话容器基础(四):重新认识Docker容器》
创新互联公司是一家集网站建设,宜良企业网站建设,宜良品牌网站建设,网站定制,宜良网站建设报价,网络营销,网络优化,宜良网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
1、Dockerfile 制作
制作rootfs 常用的方式:Dockerfile
# 使用官方提供的 Python 开发镜像作为基础镜像 FROM python:2.7-slim # 将工作目录切换为 /app WORKDIR /app # 将当前目录下的所有内容复制到 /app 下 ADD . /app # 使用 pip 命令安装这个应用所需要的依赖 RUN pip install --trusted-host pypi.python.org -r requirements.txt # 允许外界访问容器的 80 端口 EXPOSE 80 # 设置环境变量 ENV NAME World # 设置容器进程为:python app.py,即:这个 Python 应用的启动命令 CMD ["python", "app.py"]
注意事项:
1、ENTRYPOINT 和 CMD 为容器启动必需参数,docker会提供一个默认的ENTRYPOINT : /bin/sh -c ,故在不指定ENTRYPOINT 时,直接指定CMD,实际上执行的命令是/bin/sh -c CMD
2、ADD 和 COPY 的区别:ADD 可以如果添加的是一个压缩包,会自动解压,COPY不会
3、每个指令都会生成对应的镜像层,所以在写RUN的时候可以通过连接符写多个命令,避免产生过多的镜像层,例如:
RUN ln -s /data/services/nginx /usr/local/nginx && \ mkdir -p /data/weblog/nginx && \ /etc/init.d/nginx start
创建完dockerfile 通过以下命令构建镜像(在Dockerfile所在目录下)
# docker build -t test-images .
然后通过docker push 上传到镜像仓库
# docker tag test-images test/nginx:1.14.2 # docker push test/nginx:1.14.2
也可以通过commit的方式创建容器镜像,具体做法如下;
docker exec -it 4ddf4638572d /bin/sh # 在容器内部新建了一个文件 root@4ddf4638572d:/app# touch test.txt root@4ddf4638572d:/app# exit # 将这个新建的文件提交到镜像中保存 $ docker commit 4ddf4638572d geektime/helloworld:v2
docker commit 其实就是在容器起来后,加上最上层的读写层,还有原先镜像中的只读层构成镜像。其中只读层在宿主机上是共享的,不会占用额外空间。
根据联合文件系统,在镜像rootfs上做的任何更改都会在最上层先复制一层,再此基础上进行修改,也就是所谓的写时复制(copy on write)
2、docker exec 实现原理
宿主机上可以看到容器执行的进程,通过PS 看到进程pid后(假设为25686),在/proc/25686/ns 这个目录下,可以看到全部ns对应的文件
ls -l /proc/25686/ns total 0 lrwxrwxrwx 1 root root 0 Aug 13 14:05 cgroup -> cgroup:[4026531835] lrwxrwxrwx 1 root root 0 Aug 13 14:05 ipc -> ipc:[4026532278] lrwxrwxrwx 1 root root 0 Aug 13 14:05 mnt -> mnt:[4026532276] lrwxrwxrwx 1 root root 0 Aug 13 14:05 net -> net:[4026532281] lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid -> pid:[4026532279] lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid_for_children -> pid:[4026532279] lrwxrwxrwx 1 root root 0 Aug 13 14:05 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Aug 13 14:05 uts -> uts:[4026532277]
然后通过setns() 的系统调用,即可将进程加入到对应的ns中。
setns() 需要2个参数,第一个参数是要加入的namespace文件路径,如/proc/25686/ns/net;第二个参数是要执行的程序,如/bin/bash
当docker启动时指定--net=host,则容器启动时不会为进程启动network namespace,容器跟宿主机共享一个网络栈。
3、voluem实现机制
主要解决宿主机和容器之间文件互通的问题,例如:
(1) 宿主机上如何访问到容器产生的文件
(2) 容器怎么访问到宿主机上的文件
在docker上,可以通过以下两种方式实现
$ docker run -v /test ... $ docker run -v /home:/test ...
第一种方式相当于在宿主机本地创建一个temp目录,再挂载到容器的/test目录
第二种方式则是将宿主机上的/home目录挂载到容器的/test目录
本质上是使用了linux的bind mount机制,其主要作用是允许将一个目录或文件而不是这块设备挂载到指定目录上。其原理是一个inode替换的过程,在linux中,inode存放的文件内容的对象,而dentry则存放的是指向这个对象的指针。故这个挂载的过程,实际上就是修改指针,指向另外一个inode,执行umount 时则将指针指向回原来的inode。
注意:
1、在挂载目录上做的操作并不会影响源目录
2、对于挂载目录的修改,执行docker commit 时不会生效,只会创建对应的空目录