1. 程式人生 > 其它 >容器基礎4:重識docker容器

容器基礎4:重識docker容器

docker容器實際案例

1.使用docker部署python寫的web應用

from flask import Flask
import socket
import os

app = Flask(__name__)

@app.route('/')
def hello():
    html = "<h3>Hello {name} </h3><br>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)
$ cat requirements.txt
Flask

2.製作容器映象

使用Dockerfile製作docker映象,也就是rootfs

# 使用官方提供的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"]

3.Dockerfile設計思想

使用標準原語,(大寫高亮的詞語),描述我們要構建的Docker映象。並且這些原語,都是按順序處理的

FROM原語:指定"python:2.7-slim"這個官方維護的映象,從而免去安裝Python等語言環境的操作

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"
(不寫,預設是/bin/sh -c,所以實際執行的是/bin/sh -c "python ap.py",cmd的內容就是ENTRYPOINT 引數)

4.dockerfile 存放位置

Dockerfile app.py requirements.txt

5.製作docker映象

$ docker build -t helloworld .

-t:映象加Tag,docker build 會自動載入當前目錄下的Dockerfile檔案,按順序指定原語
過程:docker使用基礎映象啟動了一個容器,在容器中依次執行Dockerfile中的原語

注意事項:
docker每個原語執行後,都會生成一個對應的映象層,即使原語本身沒有明顯的修改檔案操作(env),對應的層也會存在,只不過外界看這個層是空的

6.檢視docker映象

$ docker image ls
RESPOSITORY      TAG        IMAGE  ID
helloworld            latest      653287cdf998

7.啟動容器

docker run -p 4000:80 helloworld

-p 4000:80告訴docker,把容器內的80埠對映在宿主機的4000埠上
映象名helloworld,什麼都沒寫,dockerfile中已經指定了CMDB。否組就需要些程序的啟動命令

docker run -p 4000:80 helloworld python app.py

8.檢視容器

$ 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/>

9.映象上傳DockerHub

註冊Docker Hub賬號,docker login登入
給映象起一個完整的名字geektime/helloworld:v1
geektime是賬戶名


$ docker tag helloworld geektime/helloworld:v1
$ docker push geektime/helloworld:v1

10.將正在執行的容器,直接轉為一個映象

這個容器執行起來後,我又在裡面做了一些操作,並且要把操作結果儲存到映象裡

將容器4ddf4638572d 提交為映象geektime/helloworld:v2

$ docker commit 4ddf4638572d geektime/helloworld:v2

11.docker exec 怎麼進入容器裡的呢?

程序的namespace資訊在宿主機上是真實存在的,以檔案方式存在

如下命令,可以看到docker容器在宿主機上的程序號是25686


$ docker inspect --format '{{ .State.Pid }}'  4ddf4638572d
25686

可以檢視宿主機的proc檔案,看到程序25686的所有namespace對應檔案(ns是namespace的簡寫)


$ 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]

每種namespace,在ns目錄下都對應一個虛擬檔案,並連線到真實的namespace檔案上

這樣就可以實現,將一個程序加入到一個已經存在的namespace中。(就實現了進入到程序所在容器的目的,這就是docker exec原理)