1. 程式人生 > >深入剖析Kubernetes學習筆記:深入理解獎項(08)

深入剖析Kubernetes學習筆記:深入理解獎項(08)

fix ble 允許 容器 hello 工作目錄 rwx user open

一、Python 應用案例環境

[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鏡像,並且這些原語,都是按順序處理的

需要註意的是,Dockerfile中的每個原語執行後,都會生成一個對應的鏡像層

[root@k8s-node1 Flask]# docker images|grep docker.io/python
docker.io/python

二、啟動容器以及相關操作

1、啟動容器

$ docker run -p 4000:80 helloworld

2、查看進程

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED
4ddf4638572d        helloworld       "python app.py"     10 seconds ago

3、測試是否可用

$ curl http://localhost:4000
<h3>Hello World!</h3><b>Hostname:</b> 4ddf4638572d<br/>

4、上傳鏡像到倉庫

[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#

三、docker exec 是怎麽做到進入容器裏的呢?

1、docker exec 的實現原理

[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 是怎麽做到進入容器裏的呢?

[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 的實現原理

2、docker exec 的實現原理刨析實驗

1、依賴文件

_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");
}

2、執行

[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

3、查看進程的進程的 Namespace

[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更具體的工作原理

這種通過操作系統進程相關的知識,逐步刨析Docker容器的方法,是理解容器的一個關鍵思路,希望你一定要掌握

深入剖析Kubernetes學習筆記:深入理解獎項(08)