1. 程式人生 > >Docker入門六部曲——容器

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.pyrequirements.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,不管是構建的時候還是執行的時候。