【讀書筆記】08 | 白話容器基礎(四):重新認識Docker容器

《深入剖析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。

image.png


注意:

1、在掛載目錄上做的操作並不會影響源目錄

2、對於掛載目錄的修改,執行docker commit 時不會生效,只會創建對應的空目錄


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章