Docker入門,Part 2:容器

要求

  • 已安裝Dockers1.13或更高版本
  • 完成Part 1的閱讀
  • 在機器環(huán)境上快速啟動運行一個容器保證所有都配置正確docker run hello-world

介紹

是時候開始使用Docker方式來構建一個應用了。在本節(jié)我們將基于一個應用垂直結構的底層開始構建容器。在這之上是服務,我們將在Part3第三節(jié)介紹基于容器的服務是如何在生產環(huán)境運行的。最后,在最頂層是棧,定義了所有服務的交互行為,我們將在Part5第五節(jié)進行介紹說明。

  • Stack棧
  • Services服務
  • Container容器(本節(jié)的介紹內容)

新的開發(fā)環(huán)境

在以往,如果我們要開始著手寫一個Python應用,要做的第一件事就是在機器上安裝Python的運行環(huán)境。但是,這樣會造成一個問題,就是我們搭建的環(huán)境要完美的適配應用程序的需求,同時也要匹配將來生產環(huán)境的要求。
使用Docker,我們僅僅需要做的就是構建一個便捷的Python運行環(huán)境鏡像,不再需要而外安裝其他東西。基于一個通用的鏡像我們將代碼和運行環(huán)境一起構建為一個專用鏡像,保證所有的依賴、運行環(huán)境、代碼全都在一起。
通過使用Dockerfile我們能夠定義這些非常便捷的鏡像。

使用Dockerfile定義容器

Dockerfile定義了容器是如何運轉的。類似于網絡接口和數據硬盤驅動等這些資源的使用在環(huán)境中都是虛擬化的,并且與系統(tǒng)其他程序是相互隔離的,因此我們需要將端口映射到外部,確定文件是如何來實現共通。我們期望通過Dockerfile定義配置的應用容器能夠準確無誤在任何地方運行。

Dockerfile

  • 創(chuàng)建一個空目錄
  • 切換工作路徑到這個新目錄
  • 在目錄下新建Dockerfile,將下文中的內容復制到Dockerfile中,然后保存文件(請詳細查看每個語句的注釋部分,解釋了每個語句具體的含義)
# 使用官方的Python運行環(huán)境作為基礎鏡像
FROM python:2.7-slim

# 設置工作路徑為/app
WORKDIR /app

# 復制當前目錄下的內容到容器的/app下
ADD . /app

# 安裝在文件requirements.txt指定的包
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# 將80端口進行對外開放,這樣就能從容器外部通過映射訪問容器內部的80端口
EXPOSE 80

# 定義環(huán)境變量
ENV NAME World

# 容器啟動后運行 app.py程序
CMD ["python", "app.py"]

Dockerfile中提到了有幾個我們還沒有創(chuàng)建的文件,例如app.py和requirements.txt。我們接下來進行逐一的創(chuàng)建

應用程序

我們再創(chuàng)建兩個文件,分別為requirements.txt和app.py,并將他們保存到跟Dockerfile一致的目錄。這樣我們就非常簡單的完成了應用。當上文提到的Dockerfile構建為一個鏡像后,app.py和requirements.txt也會在鏡像中,因為我們使用了Dockerfile的ADD命令,并且因為使用的EXPOSE命令我們能夠使用http協(xié)議訪問到內部的服務

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包,在應用程序中會將環(huán)境變量NAME進行打印輸出,同時還會輸出socket.gethostname()的內容。最后應為Redis并沒有運行(因為我們并沒有啟用任何的Redis服務),因此在程序中嘗試使用Redistribution會出錯同時也會輸出相關的錯誤信息。

注意:在容器中獲取機器的名稱會返回一個類似于程序進程ID一樣的容器ID

如此簡單,不需要在機器上安裝Python和相關的依賴,也不需要在機器上構建安裝這些鏡像。看上去就像我們沒有配置Python和Flask,一樣,實際上我們已經配置好了。

構建應用程序

通過上面的配置,我們已經準備好構建需要的所有。確保你的工作目錄是處于之前創(chuàng)建的新目錄。通過ls命令我們可以看到

$ ls
Dockerfile     app.py    requirements.txt

運行構建命令。將會新建一個Docker鏡像,我們可以通過使用-t參數為鏡像取一個友好的名字
docker build -t friendlyhello .
我們構建的鏡像在哪里呢?它位于機器上的本地Docker鏡像倉庫中,

docker image ls
REPOSITORY    TAG     IMAGE ID
friendlyhello latest   ******

Linux 用戶可能遇到的問題
代理服務設置
代理服務在啟動運行時能夠阻止(修改)網絡連接。如果你的機器上運行了一個代理服務器,需要將下面的相關指令添加到Dockerfile,通過使用ENV指令能夠指定代理服務的主機和端口

# 配置代理服務,修改host:port為你自己機器上的對應值
EVN http_proxy host:port
EVN https_proxy host:port

DNS設置
錯誤的DNS設置會給pip的使用帶來問題。為確保pip的正常使用,需要設置DNS服務地址。我們可以通過修改Docker守護進程里的DNS信息。通過在編輯(或者新建)配置文件(/etc/docker/daemon.json)添加dns信息

{
  "dns": ["你的DNS地址", "8.8.8.8"]
}
保存對daemon.json文件的修改,重啟docker服務`sudo service docker restart`

問題修復后,重新使用build進行構建

運行應用

使用-p參數進行端口映射將主機的4000端口映射為容器對外發(fā)布的80端口,docker run -p 4000:80 friendlyhello
通過控制臺我們可以看到容器啟動的相關信息,可以看到Python監(jiān)聽了80端口啟動了一個HTTP服務。但是這個信息是來自于容器內容,因此80端口也是指的容器內的端口,在運行啟動時我們通過端口映射將主機的4000端口映射到容器內的80,因此我們可以在本機通過http://localhost:4000來訪問服務。如果一起啟動正常我們可以在瀏覽器看到相關的信息

注意
如果是在windows7上通過Docker Toolbox來運行容器復蘇的話,需要將localhost替換為Docker Machine的IP。可以通過docker machine ip來查看Docker Machine的IP地址

在終端中使用CTRL+C,可以退出

在windows操作系統(tǒng)中,需要明確停止容器
在windows操作系統(tǒng)中,使用CTRL+C不會停止容器,只會退出命令終端。因此我們需要通過CTRL+C退出命令終端(此時通過docker container ls查看還有哪些容器在運行),然后使用docker container stop <Container NAME od ID>來停止容器

接下來,我們需要應用在后臺運行,以靜默的方式在后臺運行
docker run -d -p 4000:80 friendlyhello
使用-d參數,可以讓容器在后臺運行,通過docker container ls查看正在運行的容器和相關信息,在后臺運行的的容器可以使用docker container stop <Container NAME od ID>來停止容器

發(fā)布共享鏡像

為演示我們剛剛運行的應用的可移植性,我們可以上傳構建的鏡像然后就可以在任意地方運行了。在部署容器到其他環(huán)境(生產環(huán)境、測試環(huán)境)前,需要知道如何將鏡像推送上傳到登記注冊處。
一個登記注冊處是倉庫的集合,倉庫是鏡像的集合——就像GitHub的倉庫一樣。登記注冊處的一個賬號可以創(chuàng)建多個倉庫。docker命令默認使用Dockers的公共注冊處

注意
使用默認的注冊處是因為它已經做好了默認的配置而且是免費的。當然還有很多其他的公共注冊處提供選擇,我們也可以自己創(chuàng)建私有的注冊處

使用Docker賬號登陸

如果還沒有Docker賬號,可以在http://hub.docker.com進行注冊。在本機登陸公共的Docker登記注冊處docker login,根據提示信息輸入賬號密碼,完成登陸

為鏡像打標簽

倉庫上的鏡像與本地鏡像的關聯(lián)格式是username/repository:tag,tag是可選的,但是建議每次都附上tag,通過tag我們可以了解到docker鏡像的版本。通過鏡像功能和相關信息為repository:tag選擇有意義的名稱,例如get-started:part2
使用我們自己的username,repository和tag運行docker tag image,命令的語法格式為:
docker tag image username/repository:tag
例如
docker tag friendlyhello gordon/get-started:part2
運行docker image ls查看剛剛打上tag的鏡像

推送發(fā)布鏡像

上傳打上標簽的鏡像到倉庫
docker push username/repository:tag,例如docker push gordon/get-started:part2
上傳完成后,這個鏡像就成為公共的,如果我們登陸Docker Hub,就可以看到剛剛上傳的鏡像

從遠端拉取鏡像并運行

至此,可以通過使用 docker run在任何其他支持docker的機器上運行應用
docker run -p 4000:80 username/repository:tag
如果這個鏡像在本機沒有檢測到,Docker就會從遠端倉庫哦查找獲取這個鏡像。無論docker run在哪里運行,他都會獲取到我們上傳的鏡像,在鏡像中包含有Python、相關的依賴和運行的代碼。它把所有需要的代碼依賴組件等打包在一起,而在本地機器上我們不需要任何安裝而外的東西就能夠運行整個應用。

本節(jié)總結

本節(jié)通一個實際的案例講解了Dockefile和Docker Hub的相關知識,在下一節(jié),將會學習如何以服務的方式運行容器來擴展我們的應用

溫故知新

下面的終端記錄小視頻記錄了本節(jié)的所涉及的相關操作

下面列出了本節(jié)使用到的一些命令

docker build -t friendlyhello # 使用當前目錄下的Dockerfile新建鏡像
docker run -p 4000:80 friendlyhello # 運行“friendlyhello”,并將本機的4000端口映射到容器的80端口
docker run -d -p 4000:80 friendlyhello # 以后臺靜默方式運行容器,并將本機的4000端口映射到容器的80端口
docker container ls # 列出所有正在運行的容器
docker container ls -a # 列出所有容器,包括已停止的
docker container stop <hash> # 友好的停止指定的容器
docker contailer kill <hash> # 強制停止指定的容器
docker container rm <hash> # 從機器上刪除指定的容器
docker container rm (docker container ls -a -q) # 刪除所有容器 docker image ls -a # 列出本機上所有的鏡像 docker image rm <image_id> # 從本機上刪除指定的鏡像 docker image rm(docker image ls -a -q) # 刪除本機上所有的鏡像
docker login # 使用Docker賬號進行登陸
docker tag <image> username/repository:tag # 為待上傳的鏡像打標簽
docker push username/repository:tag # 上傳鏡像到倉庫
docker run username/repository:tag # 運行鏡像(如果本機沒有該鏡像,就會從倉庫下載鏡像并允許)

了解更多

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容