启动docker
DockerFile
FROM python: 2.7- slim
WORKDIR /app
ADD . /app
RUN pip install - - trusted- host pypi.python.org - r requirements.txt
EXPOSE 80
ENV NAME World
CMD [ "python" , "app.py" ]
FROM 原语,指定了“python:2.7-slim”这个官方维护的基础镜像 RUN 原语就是在容器里执行 shell 命令 WORKDIR,意思是在这一句之后,Dockerfile 后面的操作都以这一句指定的 /app 目录作为当前目录 CMD,意思是 Dockerfile 指定 python app.py 为这个容器的进程。这里,app.py 的实际路径是 /app/app.py。所以,CMD [“python”, “app.py”]等价于"docker run python app.py ENTRYPOINT和 CMD 都是 Docker 容器进程启动所必需的参数,完整执行格式是:“ENTRYPOINT CMD",默认情况下,Docker 会为你提供一个隐含的 ENTRYPOINT,即:/bin/sh -c。所以,在不指定 ENTRYPOINT 时,比如在我们这个例子里,实际上运行在容器里的完整进程是:/bin/sh -c “python app.py” 需要注意的是,Dockerfile 中的每个原语执行后,都会生成一个对应的镜像层。即使原语本身并没有明显地修改文件的操作(比如,ENV 原语)
docker 命令
docker build -t helloworld .
,-t表示给镜像起名字,docker build 会自动加载当前目录下的 Dockerfile 文件,然后按照顺序,执行文件中的原语。docker images
命令查看结果:
[ root@lywane app]
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
< none> < none> 6640ccb33e3b 36 minutes ago 158.3 MB
helloworld latest 8891ec087562 About an hour ago 158 MB
busybox latest 5ab5e1c8a2f0 6 months ago 1.24 MB
python 2.7 -slim 7d87e03a3906 2 years ago 147.8 MB`
docker run -p 4000:80 helloworld
,容器80端口映射到4000端口,启动docker(执行DockerFile中的CMD)。docker ps
命令查看运行中的容器:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
4ddf4638572d helloworld "python app.py" 10 seconds ago
docker tag
给镜像起名字docker push
将镜像上传到Docker Hubdocker commit
将变更提交到镜像中保存
docker exec
docker exec -it 4ddf4638572d /bin/sh
可以进入容器,是怎么做到的呢?查看容器pid
$ docker inspect --format '{{ .State.Pid }}' 4ddf4638572d
25686
$ 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]
一个进程的每种 Linux Namespace,都在它对应的 /proc/[进程号]/ns 下有一个对应的虚拟文件,并且链接到一个真实的 Namespace 文件上 有了这样一个可以“hold 住”所有 Linux Namespace 的文件,我们就可以对 Namespace 做一些很有意义事情了,比如:加入到一个已经存在的 Namespace 当中。 这也就意味着:一个进程,可以选择加入到某个进程已有的 Namespace 当中,从而达到“进入”这个进程所在容器的目的,这正是 docker exec 的实现原理 这而这个操作所依赖的,乃是一个名叫 setns()
的 Linux 系统调用,sentns接收两个参数,第一个参数是当前进程要加入的Namespace路径,比如 /proc/25686/ns/net;而第二个参数,则是你要在这个 Namespace 里运行的进程,比如 /bin/bash。 docker run -it --net container:4ddf4638572d busybox ifconfig
docker专门提供了-net选项,表示启动一个容器并加入到另一个容器的Network Namespace。指定–net=host,就意味着这个容器不会为进程启用 Network Namespace。这就意味着,这个容器拆除了 Network Namespace 的“隔离墙”,所以,它会和宿主机上的其他普通进程一样,直接共享宿主机的网络栈。这就为容器直接操作和使用宿主机网络提供了一个渠道 docker commit,实际上就是在容器运行起来后,把最上层的“可读写层”,加上原先容器镜像的只读层,打包组成了一个新的镜像。 当然,下面这些只读层在宿主机上是共享的,不会占用额外的空间。而由于使用了联合文件系统,你在容器里对镜像 rootfs 所做的任何修改,都会被操作系统先复制到这个可读写层,然后再修改。 这就是所谓的:Copy-on-Write。,Init 层的存在,就是为了避免你执行 docker commit 时,把 Docker 自己对 /etc/hosts 等文件做的修改,也一起提交掉