Docker入門六部曲——容器
準備
- 已經安裝好Docker 1.13或者以上的版本。
- 讀完的上一篇文章(基本引導)。
- 簡單的測試一下你的本地環境是否已經OK了:
docker run hello-world
。
介紹
讓我們開始構建一個Docker應用吧。這篇文章介紹的是,Docker整個結構層次中最底層的一個,那就是容器。上一個層級是服務,服務定義了容器的行為,這會在下一篇文章中介紹。最後一個,也是最高的一個層級,是堆疊,定義了所有服務的互動,這在之後也會被介紹。
- Stack(堆疊)
- Services(服務)
- Container(容器)——你正在看的
走進新的開發環境
在沒有Docker的時候,如果你想寫一個Python應用,你首先要做的是安裝一個Python的執行環境。但是,你的機器的環境必須是這樣,才能使得應用可以正常執行,而且,伺服器也必須有這樣的環境。
有了Docker,你可以直接通過映象來獲得一個Python的執行環境,不需要安裝哦。然後把你的程式碼和這個映象放到一起,當然還要加上你的程式碼所需的依賴。
這些融合在一起,就形成了一個新的映象,定義這個融合邏輯的就是Dockerfile
。
使用Dockerfile
來定義一個容器
Dockerfile
是用來定義你的容器。對於一些資源訪問,比如網絡卡、磁碟,在容器裡都是虛擬化的,和宿主機都是隔離的,因此,你必須把容器內的資源和宿主機的資源做一個對映;還需要指定你想要把哪些檔案copy到你的容器裡(比如你的程式碼)。當然,你還希望這個寫好的Dockerfile
在任何地方執行都是一樣的。
Dockerfile
建立一個空目錄,然後在裡面新建一個檔案Dockerfile
:
# 使用Python官方映象作為映象的基礎
FROM python:2.7-slim
# 設定工作空間為/app
WORKDIR /app
# 把當前目錄下的檔案拷貝到 容器裡的/app裡
ADD . /app
# 安裝requirements.txt中指定的依賴
RUN pip install -r requirements.txt
# 開放80埠
EXPOSE 80
# 設定 NAME 這個環境變數
ENV NAME World
# 當容器啟動時,執行app.py
CMD ["python" , "app.py"]
這個Dockerfile
中需要的幾個檔案還沒有準備好,app.py
和requirements.txt
,所以我們繼續吧。
應用
在Dockerfile
同一個目錄下,建立這兩個檔案。因為ADD
命令需要把這些拷貝進容器裡。而且app.py
中的伺服器輸入埠也正好是80,這會因為配置了EXPOSE
而暴露出來。
requirements.txt
:
Flask
Redis
app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "<i>cannot connect to Redis, counter disabled</i>"
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>" \
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
可以看出,pip install -r requirements.txt
安裝了Flask和Redis的庫,應用打印出NAME
這個環境變數和socket.gethostname
。最後,因為Redis沒有執行(pip安裝的只是使用Redis的庫,並不是Redis本身),所以我們應該做嘗試連線Redis,如果連線失敗就列印錯誤資訊。
注意:在容器內部訪問主機名時,會檢索容器的ID,類似於程序ID。
構建應用
就這樣!你不需要安裝Python,不需要安裝requirements.txt
中指定的任何依賴。看起來,你什麼都沒做,但是其實你已經做完了。
執行ls
(預設為類Unix環境):
$ ls
➜ demo ls
Dockerfile app.py requirements.txt
現在來執行構建命令。這個會建立一個Docker映象,-t
可以讓你給映象自定義一個名字:
docker build -t friendlyhello .
你肯定要問要,你的映象在哪裡?他就在你的本地Docker映象註冊中心:
$ docker images
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
執行你的應用
執行,當然還要對映埠號,我們需要使用-p
:
docker run -p 4000:80 friendlyhello
你可以看到Python啟動是提醒你訪問http://0.0.0.0:80
。但是不要忘記這個響應是從容器內返回的哦,而我們把容器內的80埠對映到宿主機的4000埠了,所以,我們應該訪問http://localhost:4000
。
開啟瀏覽器,可以看到:
你也可以使用curl
來看響應內容:
$ curl http://localhost:4000
<h3>Hello World!</h3><b>Hostname:</b> 8fc990912a14<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>
按鍵CTRL+C
可以退出Docker。
現在試試在後臺執行這個Docker應用:
docker run -d -p 4000:80 friendlyhello
執行完後臺執行的命令後,你可以獲得一個容器的ID
➜ demo docker run -d -p 4000:80 friendlyhello
b0054baaca448f3b30b01004de98be45fbb9aaccd850137629220bbc730b0a1a
你也可以使用docker ps
來看到縮短的容器ID:
➜ demo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b0054baaca44 friendlyhello "python app.py" About an hour ago Up About an hour 0.0.0.0:4000->80/tcp keen_beaver
當然也可以在http://localhost:4000
上看到這個容器ID。你可以使用docker stop
來結束這個程序,後面要加上容器ID哦:
➜ demo docker stop b0054baaca44
b0054baaca44
分享你的映象
為了展示Docker的便捷性,我們來嘗試上傳這個映象吧,然後再證明可以run anywhere
。
註冊中心就是一個映象的倉庫的集合——有點類似GitHub(程式碼倉庫)。一個賬號可以建立很多個倉庫。docker
預設情況下就是Docker公共註冊中心。
我們這裡使用Docker的公共註冊中心,僅僅是因為他是免費而且是預設的。不過還是有很多公開的註冊中心可以選擇的,甚至你可以設定一個私服。
登入
如果你沒有賬號,那你需要先註冊一個。
然後在你的本機上使用:
docker login
給映象打標籤
映象的標記一般這樣命名username/repository:tag
。tag是可選的,不過推薦使用tag,這樣可以給映象加一個版本。建議把倉庫名和標籤名都起得有意義一些,比如get-started:part1
。這樣會把映象放到get-started
倉庫裡,打上part1
的標籤。
語法是docker tag image username/repository:tag
,現在開始用命令來嘗試打標籤吧:
➜ demo docker tag friendlyhello dubbyyoung/get-started:part1
➜ demo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dubbyyoung/get-started part1 4ac5012183e0 4 hours ago 194 MB
friendlyhello latest 4ac5012183e0 4 hours ago 194 MB
python 2.7-slim d962f7a9f2f1 2 days ago 182 MB
hello-world latest 1815c82652c0 9 days ago 1.84 kB
➜ demo
推送到遠端
推送的命令是:
docker push username/repository:tag
我執行的結果是:
➜ demo docker push dubbyyoung/get-started:part1
The push refers to a repository [docker.io/dubbyyoung/get-started]
b57286e58751: Pushed
7b71bca6a91c: Pushed
cdc93fd01629: Pushed
553c628e7577: Mounted from library/python
8f02c55c4e74: Mounted from library/python
15d2fe96bb43: Mounted from library/python
0d960f1d4fba: Mounted from library/python
part1: digest: sha256:6d816f3a86c74e8855cef96750ff1da98eb11747c4a31cbb486b92dd20e075e6 size: 1787
隨時隨地都可以執行了
到了這一步,你可以使用docker run
在任何一個機器上運行了:
docker run -p 4000:80 username/repository:tag
如果本地沒有這個映象,Docker會自動去遠端拉取:
➜ demo docker run -p 4000:80 dubbyyoung/get-started:part1
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
注意:如果你不指定標籤
:tag
,那麼預設的就是:latest
,不管是構建的時候還是執行的時候。