事前準備:
- 安裝 Docker 1.13 以上版本
- 讀過 Part 1
- 確定你的環境,並執行 docker run hello-world
介紹:
我們可以開始用docker 的方式來建立我們的程式。 首先我們要建立container, 好讓我們的程式在上面跑。再container 上面的app, service , service, stack , 以後的章節再介紹。
- Stack
- Services
- Container (我們目前在此階段)
我的新開發環境:
以往我們要開放一支新的程式,如 Python 程式,首先必需在電腦上安裝 Python 開發環境。但這會造成你在你的主機裡建立一個你在開發 python 程式時所需的環境,但程式移到server 時,就可以跑你寫出的程式嗎?
透過 Docker,你可以只安裝 python 執行環境 包成一個 image,而不需再重新安裝一次python 環境。而且,你的image 也可以包含你開發的app,確定你的程式,和其相依套件,都可以一起包進image 內。 這種 可攜式的image, 就稱作 Dockerfile。
用 Dockerfile 來定義一個 container
Dockerfile 用來定義你想要你的container 內是什麼樣的環境,存取在這image 環境內的虛擬化的主機資源(如網路介面和磁碟檔案),因為已經被隔離在主機外了,所以你必需自己去對映 port 到外面的世界(有點像網路的 pat 或 nat)。並指定你想要把檔案 copy 進你的container 環境裡。做完後,你就可以期待你的程式在 Dockerfile內設定好而建立的docker 內,順利執行了,拿去那裡,都可以順利執竹。
Dockerfile
先建立一個空的目錄,然後把以下內容建立成一個檔案名稱叫Dockerfile 的檔案。#代表註解。
# Use an official Python runtime as a base image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
# Install any needed packages specified in requirements.txt
RUN pip install -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
這個 Dockerfile 裡面有兩個我們還沒建立的東西,即 app.py 和 requirements.txt。
app 本身
上述兩個檔案也要放在和Dockerfile同一個目錄內。這樣就可以完成我們app 的環境,簡單吧。 當上述的 Dockerfile 被建立到 image 內後,app.py 和 requirements.txt 都會被包含在內,因為Dockerfile 使用 ADD 指令。而從 app.py的輸入則可以透過HTTP來讀取,因為我們在 Dockerfile內用了EXPOSE。
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0)
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)
然後我們可以看到 在 Dockerfile 內有一行 pip install requirements.txt 安裝了 Flask 和 Radis 的Python 函式庫。而我們的app 程式列出環境變數 NAME, 當它執行到 docker.gethostname()會用到。最後,因為 Redis 無法執行(我們只是將它的 python 函式include進來,而非 Redis 程式),所以我們會得到一個錯誤訊息,而無法再繼續程式。
來建立 app 吧
好了!你不需要在你的主體主機裡安裝python 或 requirements.txt裡的東西,也不需要建立或安裝這個image 在你的主體主機裡。看來雖然好像你還沒建立好 Python 和 Flask 的環境,但實事上你已經建好了。
我們ls 一下看看:
$ ls
Dockerfile app.py requirements.txt
OK, 我們要開始建立我們的image 了。我們會用參數 -t 來建立一個 image 的名字。
docker build -t friendlyhello .
那建立出來的image 放在那呢?它會被docker 放在 你主體主機的 Docker image registry 指定的位置裡。用下列指令就可以知道 你的image 有那些:
$ docker images
REPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
執行app
要執行我們的 app.py 要先把 主體主機的 port 4000 用 -p 對映到 image 內 EXPOSE 的 port 80 :
docker run -p 4000:80 friendlyhello
其中-p 指要做 port mapping , 其中 4000 指 主體主機的 port 位,80 指 container 的 port 位,中間用 : 冒號隔開。按 Ctrl-C 離開container。
OK,那接下來我們用 -d 讓我們的app 在背景執行:
docker run -d -p 4000:80 friendlyhello
然後畫面會出現一長串的 CONTAINER ID,然會就回到你的主體主機畫面。現在,我們剛做的container 已經在背景執行了。你可以用 docker ps 來看看你有那些container 正在執行。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
1fa4ab2cf395 friendlyhello "python app.py" 28 seconds ago
現在我們可以用 docker stop 來中止我們的程式。
分享你的image
registry 是 repositories 的集合,而repository 是 image 的集合。而 registry 上的 account 可以建立許多的 repository。docker command line interface 指令 就是預設的 docker公用 registry。
如果你己經有了 Docker account, 登入 cloud.docker.com。
畫面會要求你輸入你在 cloud.docker.com 建立的帳密。
現在,我們就可以上傳我們做的image了。 在我們電腦裡的image 含在 registry 上的 repository 的表示式用 username/repository:tag ,其中 :tag 是選擇性的,但建議還是輸入,一般是用來表示這個image 的版本。
docker tag friendlyhello username/repository:tag
可以上傳了:
docker push username/repository:tag
上傳完之後,我門就可以在任何有裝docker 的電腦上,執行下列指令來啟動 我們剛裝的 image,當然,前題是要能上網。如果你沒下 :tag 指令,那它會找最新的,即它會自動加上 :latest 的tag.
現在,用你的流灠器看一下 localhost:4000 ,看是不是有正確的 hello, World 會出現。