Docker入门六部曲——容器
原文鏈接:http://www.dubby.cn/detail.html?id=8734
準(zhǔn)備
- 已經(jīng)安裝好Docker 1.13或者以上的版本。
- 讀完的上一篇文章(基本引導(dǎo))。
- 簡(jiǎn)單的測(cè)試一下你的本地環(huán)境是否已經(jīng)OK了:
docker run hello-world。
介紹
讓我們開(kāi)始構(gòu)建一個(gè)Docker應(yīng)用吧。這篇文章介紹的是,Docker整個(gè)結(jié)構(gòu)層次中最底層的一個(gè),那就是容器。上一個(gè)層級(jí)是服務(wù),服務(wù)定義了容器的行為,這會(huì)在下一篇文章中介紹。最后一個(gè),也是最高的一個(gè)層級(jí),是堆棧,定義了所有服務(wù)的交互,這在之后也會(huì)被介紹。
- Stack(堆棧)
- Services(服務(wù))
- Container(容器)——你正在看的
走進(jìn)新的開(kāi)發(fā)環(huán)境
在沒(méi)有Docker的時(shí)候,如果你想寫(xiě)一個(gè)Python應(yīng)用,你首先要做的是安裝一個(gè)Python的運(yùn)行環(huán)境。但是,你的機(jī)器的環(huán)境必須是這樣,才能使得應(yīng)用可以正常執(zhí)行,而且,服務(wù)器也必須有這樣的環(huán)境。
有了Docker,你可以直接通過(guò)鏡像來(lái)獲得一個(gè)Python的運(yùn)行環(huán)境,不需要安裝哦。然后把你的代碼和這個(gè)鏡像放到一起,當(dāng)然還要加上你的代碼所需的依賴(lài)。
這些融合在一起,就形成了一個(gè)新的鏡像,定義這個(gè)融合邏輯的就是Dockerfile。
使用Dockerfile來(lái)定義一個(gè)容器
Dockerfile是用來(lái)定義你的容器。對(duì)于一些資源訪問(wèn),比如網(wǎng)卡、磁盤(pán),在容器里都是虛擬化的,和宿主機(jī)都是隔離的,因此,你必須把容器內(nèi)的資源和宿主機(jī)的資源做一個(gè)映射;還需要指定你想要把哪些文件copy到你的容器里(比如你的代碼)。當(dāng)然,你還希望這個(gè)寫(xiě)好的Dockerfile在任何地方運(yùn)行都是一樣的。
Dockerfile
創(chuàng)建一個(gè)空目錄,然后在里面新建一個(gè)文件Dockerfile:
# 使用Python官方鏡像作為鏡像的基礎(chǔ)
FROM python:2.7-slim# 設(shè)置工作空間為/app
WORKDIR /app# 把當(dāng)前目錄下的文件拷貝到 容器里的/app里
ADD . /app# 安裝requirements.txt中指定的依賴(lài)
RUN pip install -r requirements.txt# 開(kāi)放80端口
EXPOSE 80# 設(shè)置 NAME 這個(gè)環(huán)境變量
ENV NAME World# 當(dāng)容器啟動(dòng)時(shí),運(yùn)行app.py
CMD ["python", "app.py"]
?
這個(gè)Dockerfile中需要的幾個(gè)文件還沒(méi)有準(zhǔn)備好,app.py和requirements.txt,所以我們繼續(xù)吧。
應(yīng)用
在Dockerfile同一個(gè)目錄下,創(chuàng)建這兩個(gè)文件。因?yàn)?code>ADD命令需要把這些拷貝進(jìn)容器里。而且app.py中的服務(wù)器輸入端口也正好是80,這會(huì)因?yàn)榕渲昧?code>EXPOSE而暴露出來(lái)。
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的庫(kù),應(yīng)用打印出NAME這個(gè)環(huán)境變量和socket.gethostname。最后,因?yàn)镽edis沒(méi)有運(yùn)行(pip安裝的只是使用Redis的庫(kù),并不是Redis本身),所以我們應(yīng)該做嘗試連接Redis,如果連接失敗就打印錯(cuò)誤信息。
注意:在容器內(nèi)部訪問(wèn)主機(jī)名時(shí),會(huì)檢索容器的ID,類(lèi)似于進(jìn)程ID。
構(gòu)建應(yīng)用
就這樣!你不需要安裝Python,不需要安裝requirements.txt中指定的任何依賴(lài)。看起來(lái),你什么都沒(méi)做,但是其實(shí)你已經(jīng)做完了。
執(zhí)行ls(默認(rèn)為類(lèi)Unix環(huán)境):
$ ls
? demo ls
Dockerfile app.py requirements.txt
?
現(xiàn)在來(lái)執(zhí)行構(gòu)建命令。這個(gè)會(huì)創(chuàng)建一個(gè)Docker鏡像,-t可以讓你給鏡像自定義一個(gè)名字:
docker build -t friendlyhello .
?
你肯定要問(wèn)要,你的鏡像在哪里?他就在你的本地Docker鏡像注冊(cè)中心:
$ docker imagesREPOSITORY TAG IMAGE ID
friendlyhello latest 326387cea398
?
運(yùn)行你的應(yīng)用
運(yùn)行,當(dāng)然還要映射端口號(hào),我們需要使用-p:
docker run -p 4000:80 friendlyhello
?
你可以看到Python啟動(dòng)是提醒你訪問(wèn)http://0.0.0.0:80。但是不要忘記這個(gè)響應(yīng)是從容器內(nèi)返回的哦,而我們把容器內(nèi)的80端口映射到宿主機(jī)的4000端口了,所以,我們應(yīng)該訪問(wèn)http://localhost:4000。
打開(kāi)瀏覽器,可以看到:
你也可以使用curl來(lái)看響應(yīng)內(nèi)容:
$ 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。
現(xiàn)在試試在后臺(tái)運(yùn)行這個(gè)Docker應(yīng)用:
docker run -d -p 4000:80 friendlyhello
?
執(zhí)行完后臺(tái)運(yùn)行的命令后,你可以獲得一個(gè)容器的ID
? demo docker run -d -p 4000:80 friendlyhello
b0054baaca448f3b30b01004de98be45fbb9aaccd850137629220bbc730b0a1a
?
你也可以使用docker ps來(lái)看到縮短的容器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
?
當(dāng)然也可以在http://localhost:4000上看到這個(gè)容器ID。你可以使用docker stop來(lái)結(jié)束這個(gè)進(jìn)程,后面要加上容器ID哦:
? demo docker stop b0054baaca44
b0054baaca44
?
分享你的鏡像
為了展示Docker的便捷性,我們來(lái)嘗試上傳這個(gè)鏡像吧,然后再證明可以run anywhere。
注冊(cè)中心就是一個(gè)鏡像的倉(cāng)庫(kù)的集合——有點(diǎn)類(lèi)似GitHub(代碼倉(cāng)庫(kù))。一個(gè)賬號(hào)可以創(chuàng)建很多個(gè)倉(cāng)庫(kù)。docker默認(rèn)情況下就是Docker公共注冊(cè)中心。
我們這里使用Docker的公共注冊(cè)中心,僅僅是因?yàn)樗敲赓M(fèi)而且是默認(rèn)的。不過(guò)還是有很多公開(kāi)的注冊(cè)中心可以選擇的,甚至你可以設(shè)置一個(gè)私服。
登錄
如果你沒(méi)有賬號(hào),那你需要先注冊(cè)一個(gè)。
然后在你的本機(jī)上使用:
docker login
- 1
給鏡像打標(biāo)簽
鏡像的標(biāo)記一般這樣命名username/repository:tag。tag是可選的,不過(guò)推薦使用tag,這樣可以給鏡像加一個(gè)版本。建議把倉(cāng)庫(kù)名和標(biāo)簽名都起得有意義一些,比如get-started:part1。這樣會(huì)把鏡像放到get-started倉(cāng)庫(kù)里,打上part1的標(biāo)簽。
語(yǔ)法是docker tag image username/repository:tag,現(xiàn)在開(kāi)始用命令來(lái)嘗試打標(biāo)簽吧:
? 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
?
推送到遠(yuǎn)端
推送的命令是:
docker push username/repository:tag
?
我執(zhí)行的結(jié)果是:
? 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
?
隨時(shí)隨地都可以執(zhí)行了
到了這一步,你可以使用docker run在任何一個(gè)機(jī)器上運(yùn)行了:
docker run -p 4000:80 username/repository:tag
?
如果本地沒(méi)有這個(gè)鏡像,Docker會(huì)自動(dòng)去遠(yuǎn)端拉取:
? demo docker run -p 4000:80 dubbyyoung/get-started:part1* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
?
注意:如果你不指定標(biāo)簽
:tag,那么缺省的就是:latest,不管是構(gòu)建的時(shí)候還是運(yùn)行的時(shí)候。
總結(jié)
以上是生活随笔為你收集整理的Docker入门六部曲——容器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2022-2028年中国乙丙橡胶行业市场
- 下一篇: Docker入门六部曲——Swarm