事前準備:
- 安裝 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
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。
docker login
畫面會要求你輸入你在 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 會出現。