[root@k8s-node1 Flask]# pwd /opt/Dockerfile/Flask [root@k8s-node1 Flask]# ll total 12 -rw-r--r-- 1 root root 352 Feb 1 10:08 app.py -rw-r--r-- 1 root root 518 Feb 1 10:20 Dockerfile -rw-r--r-- 1 root root 6 Feb 1 10:09 requirements.txt [root@k8s-node1 Flask]# cat app.py from flask import Flask import socket import os app = Flask(__name__) @app.route('/') def hello(): html = "<h3>Hello {name}!</h3>" \ "<b>Hostname:</b> {hostname}<br/>" return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname()) if __name__ == "__main__": app.run(host='0.0.0.0', port=80) [root@k8s-node1 Flask]# cat requirements.txt Flask [root@k8s-node1 Flask]# cat 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"]
Dockerfile的設計思想,是使用一些標準的原語(即大寫高亮的詞語),描述咱們所要構建的Docker鏡像,而且這些原語,都是按順序處理的html
須要注意的是,Dockerfile中的每一個原語執行後,都會生成一個對應的鏡像層node
[root@k8s-node1 Flask]# docker images|grep docker.io/python docker.io/python
$ docker run -p 4000:80 helloworld
$ docker ps CONTAINER ID IMAGE COMMAND CREATED 4ddf4638572d helloworld "python app.py" 10 seconds ago
$ curl http://localhost:4000 <h3>Hello World!</h3><b>Hostname:</b> 4ddf4638572d<br/>
[root@k8s-node1 ~]# docker exec -it 900e7b6e1984 /bin/sh# # touch test.txt# # exit# [root@k8s-node1 ~]# docker tag helloworld 10.0.128.4:500/helloworld:v1# [root@k8s-node1 ~]# docker push 10.0.128.4:500/helloworld:v1# The push refers to a repository [10.0.128.4:500/helloworld]# Get https://10.0.128.4:500/v1/_ping: dial tcp 10.0.128.4:500: getsockopt: connection refused "/bin/sh" 2 days ago Exited (137) 2 days ago grave_mclean#
[root@k8s-node1 Flask]# docker exec -it 43c49903582e /bin/sh # pwd /app # ls Dockerfile app.py requirements.txt test.txt
這裏,我使用了docker exec 命令進入到了容器當中,在瞭解了Linux Namespace的隔離機制後,你應該會很天然地想到一個問題
docker exec 是怎麼作到進入容器裏的呢?python
[root@k8s-node1 Flask]# docker inspect --format '{{ .State.Pid }}' 43c49903582e 2400 [root@k8s-node1 opt]# ls -l /proc/2400/ns total 0 lrwxrwxrwx 1 root root 0 Feb 20 17:20 ipc -> ipc:[4026532495] lrwxrwxrwx 1 root root 0 Feb 20 17:19 mnt -> mnt:[4026532493] lrwxrwxrwx 1 root root 0 Feb 20 17:19 net -> net:[4026532498] lrwxrwxrwx 1 root root 0 Feb 20 17:20 pid -> pid:[4026532496] lrwxrwxrwx 1 root root 0 Feb 20 17:23 user -> user:[4026531837] lrwxrwxrwx 1 root root 0 Feb 20 17:20 uts -> uts:[4026532494]
這也就意味着:一個進程,能夠選擇加入到某個進程已有的 Namespace 當中,從而達到「進入」這個進程所在容器的目的,這正是 docker exec 的實現原理linux
一、依賴文件docker
_startmainopen@@GLIBC_2.2.5perror@@GLIBC_2.2.5_Jv_RegisterClassesexecvp@@GLIBC_2.2.5exit@@GLIBC_2.2.5__TMC_END___ITM_registerTMCloneTable_init [root@k8s-node1 opt]# cat set_ns.c #define _GNU_SOURCE #include <fcntl.h> #include <sched.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE);} while (0) int main(int argc, char *argv[]) { int fd; fd = open(argv[1], O_RDONLY); if (setns(fd, 0) == -1) { errExit("setns"); } execvp(argv[2], &argv[2]); errExit("execvp"); }
二、執行flask
[root@k8s-node1 opt]# gcc -o set_ns set_ns.c [root@k8s-node1 opt]# ./set_ns /proc/2400/ns/net /bin/bash [root@k8s-node1 opt]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.16.6.2 netmask 255.255.255.0 broadcast 0.0.0.0 inet6 fe80::42:acff:fe10:602 prefixlen 64 scopeid 0x20<link> ether 02:42:ac:10:06:02 txqueuelen 0 (Ethernet) RX packets 8 bytes 648 (648.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 648 (648.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
三、查看進程的進程的 Namespacebash
[root@k8s-node1 opt]# ps aux|grep /bin/bash root 2615 0.1 0.0 116204 2876 pts/0 S 17:28 0:00 /bin/bash root 2652 0.0 0.0 112660 972 pts/0 R+ 17:28 0:00 grep --color=auto /bin/bash [root@k8s-node1 opt]# ls -l /proc/2615/ns/net lrwxrwxrwx 1 root root 0 Feb 20 17:30 /proc/2615/ns/net -> net:[4026532498] [root@k8s-node1 opt]# ls -l /proc/2400/ns/net lrwxrwxrwx 1 root root 0 Feb 20 17:19 /proc/2400/ns/net -> net:[4026532498]
轉了一個大圈子,我實際上是爲你詳細解讀了這個操做背後,linux namespace更具體的工做原理app
這種經過操做系統進程相關的知識,逐步刨析Docker容器的方法,是理解容器的一個關鍵思路,但願你必定要掌握curl