1. 程式人生 > >Docker之旅:在Docker容器中建立第一個程式

Docker之旅:在Docker容器中建立第一個程式

Docker的概念

Docker是開發人員和系統管理員 使用容器開發,部署和執行應用程式的平臺。使用Linux容器來部署應用程式稱為集裝箱化。容器不是新的事物,但它們用於輕鬆部署應用程式。

一、測試一下Docker的版本

1. 檢視Docker版本的資訊

執行docker –version並確保您擁有受支援的Docker版本:

root@iZbp162mb58mqtz72o389nZ:~# docker --version
Docker version 18.03.1-ce, build 9ee9f40
root@iZbp162mb58mqtz72o389nZ:~# 

2. 檢視Docker的更多的資訊

執行docker info或(docker version不–)檢視關於docker安裝的更多詳細資訊:

root@iZbp162mb58mqtz72o389nZ:~# docker info
Containers: 3
 Running: 0
 Paused: 0
 Stopped: 3
Images: 1
Server Version: 18.03.1-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver
: json-file Cgroup Driver: cgroupfs ......

3. 測試Docker安裝

通過執行簡單的Docker映象hello-world來測試您的安裝是否工作正常 :

[email protected]:~# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1.
The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash ......

4. 列出hello-world下載到您的機器的影象

root@iZbp162mb58mqtz72o389nZ:~# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              e38bc07ac18e        5 weeks ago         1.85kB
root@iZbp162mb58mqtz72o389nZ:~# 

5. 列出hello-world顯示訊息後退出的容器(由影象衍生)。如果它仍在執行,則不需要該–all選項:

root@iZbp162mb58mqtz72o389nZ:~# docker container ls --all
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
72b99c9c6652        hello-world         "/hello"            6 minutes ago       Exited (0) 6 minutes ago                       elegant_bhaskara
ef4105062f3c        hello-world         "/hello"            22 hours ago        Exited (0) 22 hours ago                        elegant_shannon
8eeb4f85babc        hello-world         "/hello"            22 hours ago        Exited (0) 22 hours ago                        sleepy_bartik
64c8a1708411        hello-world         "/hello"            22 hours ago        Exited (0) 22 hours ago                        dreamy_ride
root@iZbp162mb58mqtz72o389nZ:~# 

6. Docker的一些命令

## List Docker CLI commands
docker
docker container --help

## Display Docker version and info
docker --version
docker version
docker info

## Execute Docker image
docker run hello-world

## List Docker images
docker image ls

## List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls --all
docker container ls -aq

二、Docker容器配置

1. 容器所處的位置

現在是開始以Docker方式構建應用程式的時候了。我們從這種應用程式的層次結構的底部開始,這是一個容器,我們將在此頁面上介紹。在這個層次上面是一個服務,它定義了容器在生產中的行為方式,最後,在頂層是堆疊。

  • 服務
  • 容器(你在這裡)

2. 你新的開發環境

過去,如果您要開始編寫Python應用程式,您的第一個業務就是將Python執行開發環境安裝到您的機器上。
但是,這會造成您的計算機上的環境需要完美適合您的應用程式按預期執行,並且還需要與您的生產環境相匹配。
使用Docker,您可以將一個可移植的Python執行時作為一個映像獲取,無需安裝。然後,您的構建可以將基礎Python影象與應用程式程式碼一起包括在內,確保您的應用程式,依賴項和執行時都一起旅行。
這些行動式影象是由稱為a的東西定義的Dockerfile

3. 定義一個容器 Dockerfile

Dockerfile定義您的容器內環境中發生了什麼。訪問網路介面和磁碟驅動器等資源是在此環境中虛擬化的,與系統的其餘部分隔離,因此您需要將埠對映到外部世界,並明確要將哪些檔案“複製”到那個環境。但是,在完成這些之後,您可以期望在其中定義的應用程式的構建 Dockerfile在其執行的任何位置都完全相同。

root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# ls
Dockerfile
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# vi Dockerfile 

編輯一下Dockerfile

# Use an official Python runtime as a parent 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 --trusted-host pypi.python.org -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"]

其中最重要的檔案有兩個,一個是:requirements.txt,一個是:app.py

4、應用程式本身

再建立兩個檔案,requirements.txt然後app.py將它們放在同一個資料夾中Dockerfile。這完成了我們的應用程式,您可以看到它非常簡單。當上述Dockerfile被內建到的影象,app.py和 requirements.txt是因為存在Dockerfile的ADD命令,並從輸出app.py是通過HTTP得益於訪問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為Python安裝Flask和Redis庫,並且該應用程式輸出環境變數NAME以及呼叫的輸出socket.gethostname()。最後,因為Redis沒有執行(因為我們只安裝了Python庫,而不是Redis本身),所以我們應該期望在這裡使用它的嘗試失敗併產生錯誤訊息。

  • 注意:在容器中訪問主機的名稱將檢索容器ID,這與正在執行的可執行檔案的程序ID相似。

好啦,您requirements.txt的系統中不需要Python或其他任何東西,也不需要在系統上安裝或執行此映像。看起來你並沒有真正用Python和Flask建立一個環境,但是你已經擁有了。

5. 構建應用程式

我們準備構建應用程式。確保您仍然處於新目錄的頂層。以下是ls應該顯示的內容:

root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# ls
Dockerfile  app.py  requirements.txt
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# 

現在執行build命令。這會建立一個Docker映象,我們將使用-t它來標記,因此它有一個友好的名稱。

ocker build -t friendlyhello .
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker build -t friendlyhello .
Sending build context to Docker daemon  4.608kB
Step 1/7 : FROM python:2.7-slim
 ---> 46ba956c5967
Step 2/7 : WORKDIR /app
 ---> Using cache
 ---> f3b2fb3956fe
......
Successfully tagged friendlyhello:latest
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# 

我構建的映象跑到哪裡去了?他們在你本地的映象庫裡面:friendlyhello這個就是的。

root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
friendlyhello       latest              99fa0c4345cf        4 minutes ago       151MB
<none>              <none>              e21d979e3223        6 minutes ago       140MB
python              2.7-slim            46ba956c5967        12 days ago         140MB
hello-world         latest              e38bc07ac18e        5 weeks ago         1.85kB
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# 

如果有停止一個映象,可能需要強制停止

root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker rmi 99fa0c4345cf --force
Untagged: friendlyhello:latest
Deleted: sha256:99fa0c4345cf9dd423945342f0d2fa4b460e36932edf58c0973fc991e5068d24
Deleted: sha256:f6071820b82680b2eb179a8bc5584451f6e69c2672ef3989040698fa36a66f13
Deleted: sha256:517f33d026cd6ba5ce5433aa4ee575a6e47aa228030c76fda1ffe6ded5abca10
Deleted: sha256:7564cd520ac57faa1032a04f6b7894c09fb08d4e6349c80377d9b74666135274
Deleted: sha256:585d0dbb4c234c5243d8098c175565dc8158968537f4904b5797f6b0aca88977

6、如果有故障了,就看看這裡(針對Linux使用者的故障排除)

代理伺服器在啟動並執行後可以阻止與您的網路應用程式的連線。如果您位於代理伺服器的後面,請使用以下ENV命令為代理伺服器指定主機和埠,將以下行新增到Dockerfile中:

# Set proxy server, replace host:port with values for your servers
ENV http_proxy host:port
ENV https_proxy host:port

代理伺服器設定
DNS錯誤配置可能會產生問題pip。您需要設定您自己的DNS伺服器地址才能pip正常工作。您可能需要更改Docker守護程式的DNS設定。您可以/etc/docker/daemon.json使用dns金鑰編輯(或建立)配置檔案,如下所示:

{
  "dns": ["your_dns_address", "8.8.8.8"]
}

在上面的例子中,列表的第一個元素是你的DNS伺服器的地址。第二項是Google的DNS,當第一項不可用時可以使用它。
在繼續之前,儲存daemon.json並重新啟動泊塢窗服務。
sudo service docker restart
一旦修復,重試執行build命令。

7、執行應用程式

執行應用程式,使用以下命令將計算機的埠4000對映到容器的已釋出埠80 -p:下面這樣就是執行成功了

root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker run -p 4000:80 friendlyhello
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

您應該看到Python正在為您的應用提供服務的訊息http://0.0.0.0:80。但是該訊息來自容器內部,它不知道你將該容器的埠80對映到4000,從而製作正確的URL http://localhost:4000

  • 那麼我現在要從外部去訪問它,如果是阿里雲的話,需要開啟安全組
    這裡寫圖片描述
  • 通過ip:埠的方式來訪問
    這裡寫圖片描述
  • 後臺執行
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker run -p 4000:80 friendlyhello
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
45.76.53.148 - - [17/May/2018 09:29:05] "GET / HTTP/1.1" 200 -
45.76.53.148 - - [17/May/2018 09:29:06] "GET /favicon.ico HTTP/1.1" 404 -

這種方式按Ctrl+C就退出了,不好,我們要在後臺執行,只需要多一個-d就可以了。

root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker run -d -p 4000:80 friendlyheol 
ca08a914abea5290bb7cdf422c335b77738fc23e7f6c6ba596165a021daf4584
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# 

8、檢視正在執行的容器(一個程式對應一個容器)

docker container ls
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                  NAMES
ca08a914abea        friendlyhello       "python app.py"     About a minute ago   Up About a minute   0.0.0.0:4000->80/tcp   friendly_minsky
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# 

9、停止這個程式,結束這個程序

現在docker container stop用來結束這個過程,使用CONTAINER ID如下所示:

//檢視container Id
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS                  NAMES
ca08a914abea        friendlyhello       "python app.py"     About a minute ago   Up About a minute   0.0.0.0:4000->80/tcp   friendly_minsky
//結束
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker container stop ca08a914abea
ca08a914abea
//沒有了
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# docker container ls
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
root@iZbp162mb58mqtz72o389nZ:~/docker/pythontest# 

三、分享我的映象

1.為了演示我們剛才建立的可移植性,我們上傳我們構建的映像並在其他地方執行它。畢竟,當您想要將容器部署到生產環境時,您需要知道如何推送登錄檔。

登錄檔是儲存庫的集合,而儲存庫是影象的集合 - 有點像GitHub儲存庫,但程式碼已經建立。登錄檔上的帳戶可以建立許多儲存庫。該dockerCLI使用公共登錄檔預設情況下。

注意:我們在這裡使用Docker的公共登錄檔僅僅是因為它是免費和預先配置的,但有許多公共選項可供選擇,甚至可以使用Docker Trusted Registry設定您自己的私有登錄檔。

2.使用您的Docker ID登入

如果您沒有Docker帳戶,請在cloud.docker.com註冊一個帳戶 。記下你的使用者名稱。

2.1 登入到本地計算機上的Docker公共登錄檔。

[email protected]:~# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: xiongben
Password: 
Login Succeeded
[email protected]:~# 

2.2 標記影象

將本地映像與登錄檔中的儲存庫相關聯的符號是 username/repository:tag。該標籤是可選的,但建議使用,因為它是註冊管理機構用於為Docker映象提供版本的機制。為該上下文提供儲存庫並標記有意義的名稱,例如 get-started:part2。這將影象放入get-started儲存庫並標記為part2。
現在,把它放在一起來標記影象。docker tag image使用您的使用者名稱,儲存庫和標籤名稱執行,以便將影象上傳到您想要的目的地。該命令的語法是:

docker tag image username/repository:tag

執行如下:

root@iZbp162mb58mqtz72o389nZ:~# docker tag friendlyhello xiongben/get-started:part2

2.3 需要去建立一個docker的倉庫

例如我建立了一個get-started。
docke cloud
這裡寫圖片描述

2.4 執行docker影象ls以檢視新標記的影象。

[email protected]:~# docker image ls
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
friendlyhello          latest              7f2dee16bc71        2 hours ago         151MB
xiongben/get-started   part2               7f2dee16bc71        2 hours ago         151MB
<none>                 <none>              e21d979e3223        2 hours ago         140MB
python                 2.7-slim            46ba956c5967        12 days ago         140MB
hello-world            latest              e38bc07ac18e        5 weeks ago         1.85kB

2.5 釋出映象

[email protected]:~# docker push xiongben/get-started:part2
The push refers to repository [docker.io/xiongben/get-started]
bb1832784221: Pushed 
3769158c31ac: Pushed 
2ac6ade48cac: Pushed 
a40d037570f2: Mounted from library/python 
4e1a46391216: Mounted from library/python 
10dd6271862c: Mounted from library/python 
ba291263b085: Mounted from library/python 
part2: digest: sha256:ce25797c1fb3d95fc7393f015ea584be0c110e0469e186813ee755f41f76922a size: 1787
[email protected]:~# 

2.6 看下這樣就成功了

[email protected]:~# docker push xiongben/get-started:part2
The push refers to repository [docker.io/xiongben/get-started]
bb1832784221: Pushed 
3769158c31ac: Pushed 
2ac6ade48cac: Pushed 
a40d037570f2: Mounted from library/python 
4e1a46391216: Mounted from library/python 
10dd6271862c: Mounted from library/python 
ba291263b085: Mounted from library/python 
part2: digest: sha256:ce25797c1fb3d95fc7393f015ea584be0c110e0469e186813ee755f41f76922a size: 1787
[email protected]:~# 

四、從遠端儲存庫中提取並執行影象

從現在開始,您可以使用docker run此命令在任何機器上使用並執行您的應用程式

docker run -p 4000:80 username/repository:tag

那麼來執行一下試一試:

[email protected]:~# docker run -p 4000:80 xiongben/get-started:part2
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)

訪問一下:
這裡寫圖片描述

  • 無論在哪裡docker run執行,它都會將您的影象,Python以及所有依賴項從中拉出requirements.txt,然後執行您的程式碼。它們都在一個整潔的小包中一起旅行,並且您不需要在主機上安裝任何Docker來執行它(意思是這樣你的機器上安裝的docker環境,你不需要再將程式傳上去,直接從cloud上拉出來,就可以運行了)。

好啦,完成啦!