本章中,我們將一起來學習Portainer。Portainer是一個允許我們通過網頁界面管理Docker資源的工具。本章將涵蓋如下主要內容:
Portainer的發展歷程
- 設置和運行Portainer
- 使用Portainer和Docker Swarm
技術准備
和此前章節一樣,我們將繼續使用本地Docker軟件。同樣,本章中的截圖來自我個人偏好的操作系統macOS。在本章的最后,我們將使用Docker Machine和VirtualBox來啟動本地Docker Swarm集群。
如前,我們所運行的Docker命令可以在安裝了Docker的三種操作系統上運行,但其中有少量的支持命令,可能僅能在macOS和Linux操作系統中使用。
觀看如下視頻可查看實時代碼操作效果:
Portainer的歷程
在我們擼起袖子安裝和運行Portainer之前,先來談談這個項目的背景。本書的第一版講到過Docker UI。Docker UI由Michael Crosby編寫,在開發一年之后將該項目轉交給了Kevan Ahlquist。正是在這一階段,由於商標的問題,該項目被重命名為UI for Docker。
UI for Docker的開發持續到Docker開始在核心Docker引擎中加速引入一些功能如Swarm模式。在這期間 UI for Docker項目被復制到了后來成為Portainer的項目中,它的第一個大版本發布在2016年6月。
在初次公開發布之后,Portainer幕后團隊評估大部分代碼已更新或重寫,於2017年中,添加了新功能,諸如其於角色的控制和對Docker Compose的支持。
2016年12月,UI for Docker的GitHub倉庫中提交了一份通知,說明該項目已過時,應使用Portainer。
啟動和運行Portainer
首先來看使用Portainer來管理本地運行的單Docker實例。我使用的是Docker for macOS,但操作指南應該適用其它系統安裝的Docker。
- 首先,只需運行如下命令來從Docker Hub抓取容器鏡像
12$ docker image pull portainer/portainer$ docker image ls - 可以通過運行docker image ls命令查看到,Portainer的鏡像僅為74.1MB。啟動Portainer,我們只需在macOS或Linux上運行如下命令:
1234$ docker container run -d \-p 9000:9000 \-v /var/run/docker.sock:/var/run/docker.sock \portainer/portainer - Windows用戶需要運行如下命令:
12$ docker container run -d -p 9000:9000 -v\\.\pipe\docker_engine:\\.\pipe\docker_engine portainer/portainerℹ️可以從剛剛運行的命令中看出,我們在Docker主機上為Docker引擎掛載了套接字文件。這么做可以允許Portainer對宿主機上的Docker引擎擁有全部的訪問權限。這樣它能管理主機上的Docker,但這也意味着Portainer對宿主機擁有了全部的權限,需要在訪問時以及在遠程主機上對外暴露Portainer時要格外小心。
以下是在macOS執行時的顯示:
123456789101112131415$ docker image pull portainer/portainerUsing default tag: latestlatest: Pulling from portainer/portainerd1e017099d17: Pull complete0b1e707a06d2: Pull completeDigest: sha256:d6cc2c20c0af38d8d557ab994c419c799a10fe825e4aa57fea2e2e507a13747dStatus: Downloaded newer image for portainer/portainer:latest$ docker image lsREPOSITORY TAG IMAGE ID CREATED SIZEportainer/portainer latest 19d07168491a 7 weeks ago 74.1MB$ docker container run -d \> -p 9000:9000 \> -v /var/run/docker.sock:/var/run/docker.sock \> portainer/portainer973962fbfa9c8d5fc2368aa868be9a8c1bffc97b9fdae2330aa1a87c90a02b3a - 對於最基本類型的安裝,我們只需要運行這些命令。還有一些步驟可以完善這一安裝,都是在瀏覽器中進行執行的。訪問http://localhost:9000/來進行完善。
第一個歡迎頁面是要求你為admin用戶設置密碼。 - 設置好密碼后,你會進入到登錄頁面:輸入用戶名admin和你剛剛配置的密碼。在登錄后,會詢問你所想要管理的Docker實例。有兩個選項:
- 管理Portainer運行處的Docker實例
- 管理遠程Docker實例
此時,我們想要管理Portainer所運行處的實例,即本地選項,而非默認的遠程選項:
因為我們已經在啟動我們的Portainer容器時考慮到了掛載的Docker套接字文件,可以點擊Connect來完成安裝。這樣就會直接進入到Portainer本身,並顯示儀表盤。
使用Portainer
現在我們已經運行了Portainer並配置與我們的Docker軟件進行通訊,我們可以開操作左側菜單上的任意功能,最上面的為儀表盤,也是Portainer軟件的默認落腳頁。
儀表盤
從下圖中可以看出,儀表盤為我們展示了配置為與Portainer通訊的Docker實例當前狀態的一個概覽:
我這里顯示了運行的容器數,當前僅有一個運行中的Portainer容器,還有一個我下載的鏡像(譯者本機原有鏡像未刪除,數量略多)。我們還可以看到Docker實例上可用的數據卷及網絡的數量,同時它還會顯示運行中的棧的數量。
它還顯示了Docker實例自身的一些基本信息,可以看到Docker實例運行的是Moby Linux,有兩個 CPU 和2 GB內存。這是Docker for Mac的默認配置。
儀表盤會根據Portainer所運行的環境來進行適配,我們在后面將Portainer關聯到Docker Swarm集群時會再次進行訪問。
應用模板
接着,我們來App模板。這一版塊可能是唯一不直接存在於核心Docker引擎中的功能,它是從Docker Hub上下載容器來運行常用應用的一種方式:
Portainer中默認帶有大約25個模板。模板以JSON格式進行定義。例如,nginx模板內容是這樣的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
{
"type": "container",
"title": "Nginx",
"description": "High performance web server",
"categories": ["webserver"],
"platform": "linux",
"logo": "https://portainer-io-assets.sfo2.digitaloceanspaces.com/logos/nginx.png",
"image": "nginx:latest",
"ports": [
"80/tcp",
"443/tcp"
],
"volumes": ["/etc/nginx", "/usr/share/nginx/html"]
}
|
你還可以添加更多選項,例如MariaDB的模板文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
{
"type": "container",
"title": "MariaDB",
"description": "Performance beyond MySQL",
"categories": ["database"],
"platform": "linux",
"logo": "https://portainer-io-assets.sfo2.digitaloceanspaces.com/logos/mariadb.png",
"image": "mariadb:latest",
"env": [
{
"name": "MYSQL_ROOT_PASSWORD",
"label": "Root password"
}
],
"ports": [
"3306/tcp"
],
"volumes": ["/var/lib/mysql"]
}
|
可以看到,模板文件和Docker Compose文件非常相似,但這種格式僅用於Portainer。大部分選項的意思都一目了然,這里我們要講到Name和Label選項。
對於通過環境變量傳遞自定義值來定義選項的容器,Name和Label選項讓你可以在容器啟動前要完成的自定義表單項展示給客戶,如下圖所示:
可以看到,我們可以輸入一個希望MariaDB容器使用的root密碼字段。填寫該字段會將值作為環境變量進行傳遞,構建如下命令來啟動容器:
1
|
$ docker container run --name [Name of Container] -p 3306 -e MYSQL_ROOT_PASSWORD=[Root password] -d mariadb:latest
|
有關應用模板的更多信息,我推薦查看文檔,在本章的擴展閱讀部分可以找到相關鏈接。
容器
接下來看的左側菜單是Containers。在這里我們啟動Docker實例上運行的容器並與其交互。點擊Containers菜單項會進入一個所有容器的列表,包含Docker實例上運行中和停止的容器。
可以看到,當前我只運行了一個容器,這正是Portainer容器。我們先不與它進行交互,點擊+ Add container按鈕來添加一個運行前面章節使用的cluster應用的容器。
在Create container頁面上有好幾個選項,可以填入如下內容:
- Name: cluster
- Image: russmckendrick/cluster
- Always pull the image: On
- Publish all exposed ports: On
最后,點擊+ map additional port按鈕來添加8080端口到容器的80端口的端口映射。完成后的表單類似下圖:
完成后,點擊Deploy the container,等待幾秒,會返回一個運行中容器的列表,此時可以看到新運行的容器:
使用列表中每個容器左側的復選框可以激活頂部的按鈕,通過它們可以控制容器的狀態,確保不要Kill或刪除掉Portainer容器。點擊容器的名稱,比如cluster,會顯示容器本身更多的信息:
可以看到,這里獲得的容器的相關信息與運行如下命令所獲取的信息相同:
1
|
$ docker container inspect cluster
|
通過點擊Inspect可以看到完整的輸出。還可以看到有針對 統計、日志和控制台的按鈕。
統計
Stats頁面顯示CPU、內存和網絡工具,以及所檢查的容器的進程列表:
如果保持頁面打開圖表會自動刷新,重新刷新頁面會將圖中的值置為0,從頭開始記錄。這是因為Portainer是使用如下命令通過Docker API來接收這一信息的:
1
|
$ docker container stats cluster
|
每次刷新頁面時,該命令就從頭開始,因為Portainer當前沒有在后台輪詢Docker來記錄每個運行中容器的數據。
日志
接着來看Logs頁面。它顯示運行如下命令的結果:
1
|
$ docker container logs cluster
|
這顯示STDOUT及STDERR的日志:
你還可以為輸出添加時間戳,與運行如下命令是相同的:
1
|
$ docker container logs --timestamps cluster
|
控制台
最后,還有Console。這會打開一個HTML5終端並允許你登錄到運行中的容器中。在連接到容器前,你需要選擇一個shell。有三種shell可供選擇:/bin/bash , /bin/sh或/bin/ash,還可以選擇連接所用的用戶,默認為root。雖然cluster鏡像兩種都進行了安裝,我選擇使用/bin/bash:
1
|
$ docker container exec -it cluster /bin/sh
|
從截圖中可以看到,bash進行的PID為13。這個進程由docker container exec命令所創建,它是在從shell會話中斷連接后會終止的唯一一個進程。
鏡像
接下來一起來看左側菜單Images。通過這里,你可以管理、下載及上傳鏡像:
在頁面的頂部,你可以選擇拉取鏡像。例如,在輸入框中輸入amazonlinux,然后點擊Pull the Image會從 Docker Hub下載一個亞馬遜Linux容器鏡像的拷貝。Portainer所執行的命令為:
1
|
$ docker image pull amazonlinux
|
你可以通過點擊鏡像ID來查找各個鏡像的更多信息,這時會進入到一個對運行如下命令的輸出進行美化渲染的頁面:
1
|
$ docker image inspect russmckendrick/cluster
|
查看如下截圖:
你不僅可以獲得有關鏡像的所有信息,還可以選擇推送鏡像的拷貝到所選擇的倉庫,默認為Docker Hub。
你還可以看到鏡像中所包含的各層的完整做好事,顯示在構建時所執行的命令以及各層的大小。
網絡和數據卷
菜單中接下來的兩項供我們管理網絡和數據卷。我不會在這里過多討論,因為它們本身也沒太多可說的。
網絡
這里你可以使用默認的bridge驅動器快速地添加一個網絡。點擊高級設置會進入一個包含更多選項的頁面。包括使用其它驅動器、定義子網、添加標簽和限制對網絡的外部訪問(譯者注:新版已合並至一個頁面)。和其它版塊一樣,你可以刪除網絡以及檢查已有網絡。
數據卷
這里除添加或刪除數據卷外並沒有太多選項。在添加數據卷時,你可以選擇驅動器以及填寫傳遞給驅動器的選項,這允許我們使用第三方驅動器插件。除此之外沒什么可以再了解的了,連檢查的選項都沒有。
事件
events頁面顯示過去24小時的所有事件,你還可以對結果進行過濾,這樣可以快速找到需要查找的信息:
這相當於運行如下命令:
1
|
$ docker events --since '2019-04-24T8:30:00' --until '2019-04-25T8:30:00'
|
引擎
最后一條僅僅是輸出如下信息:
1
|
$ docker info
|
以下顯示了該命令的輸出:
如果你在定位多個Docker實例端點並需要知道端點所運行的環境時這會非常有用。
譯者注:新版界面中有一些變化
到這里我們將進一步了解在Docker Swarm上運行Portainer,所以可以刪除運行中的容器以及在啟動Portainer時所創建的數據卷,你可以使用如下命令刪除數據卷:
1
|
$ docker volume prune
|
Portainer和Docker Swarm
前面一節,我們一起看了如何在獨立的Docker實例上使用Portainer。Portainer還支持Docker Swarm集群,以及適配集群環境的界面選項。我們先來創建一個Swarm,然后啟動Portainer來作為一個服務並查看變化。
創建Swarm
如同Docker Swarm一章那樣,我們將使用Docker Machine來本地創建一個Swarm,只需要運行如下命令:
1
2
3
|
$ docker-machine create -d virtualbox swarm-manager
$ docker-machine create -d virtualbox swarm-worker01
$ docker-machine create -d virtualbox swarm-worker02
|
啟動了這三個實例之后,運行如下命令來初始化Swarm:
1
2
3
|
$ docker $(docker-machine config swarm-manager) swarm init \
--advertise-addr $(docker-machine ip swarm-manager):2377 \
--listen-addr $(docker-machine ip swarm-manager):2377
|
然后運行如下命令,插入你自己的令牌來添加worker節點:
1
2
3
4
5
6
7
|
$ SWARM_TOKEN=SWMTKN-1-45acey6bqteiro42ipt3gy6san3kec0f8dh6fb35pnv1xz291v-4l89ei7v6az2b85kb5jnf7nku
$ docker $(docker-machine config swarm-worker01) swarm join \
--token $SWARM_TOKEN \
$(docker-machine ip swarm-manager):2377
$ docker $(docker-machine config swarm-worker02) swarm join \
--token $SWARM_TOKEN \
$(docker-machine ip swarm-manager):2377
|
現在已經形成了集群,運行如下命令來將本地Docker客戶端指向manager節點:
1
|
$ eval $(docker-machine env swarm-manager)
|
最后,使用如下命令查看Swarm的狀態:
1
|
$ docker node ls
|
Portainer服務
現在已經有了一個Docker Swarm集群,並且本地客戶端已配置與manager節點進行通訊,我們只需通過運行如下命令來啟動Portainer服務:
1
2
3
4
5
6
7
|
$ docker service create \
--name portainer \
--publish 9000:9000 \
--constraint 'node.role == manager' \
--mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
portainer/portainer \
-H unix:///var/run/docker.sock
|
可以看到,這會在manager節點上啟動Portainer來作為服務,並讓服務掛載manager節點的套接字文件,這樣Swarm中其它節點對其都可見。你可以通過運行如下命令來查看服務啟動是否有報錯:
1
2
|
$ docker service ls
$ docker service inspect portainer --pretty
|
以下顯示了輸出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
$ docker service inspect portainer --pretty
ID: dxfw2ofanczjpjkviljv32pyt
Name: portainer
Service Mode: Replicated
Replicas: 1
Placement:
Constraints: [node.role == manager]
UpdateConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
RollbackConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Rollback order: stop-first
ContainerSpec:
Image: portainer/portainer:latest@sha256:d6cc2c20c0af38d8d557ab994c419c799a10fe825e4aa57fea2e2e507a13747d
Args: -H unix:///var/run/docker.sock
Init: false
Mounts:
Target: /var/run/docker.sock
Source: /var/run/docker.sock
ReadOnly: false
Type: bind
Resources:
Endpoint Mode: vip
Ports:
PublishedPort = 9000
Protocol = tcp
TargetPort = 9000
PublishMode = ingress
|
現在已啟動了服務,你可以使用集群中任意節點的 IP 上的9000端口來訪問Portainer,或者運行如下命令:
1
|
$ open http://$(docker-machine ip swarm-manager):9000
|
頁面打開時,你會再次被要求為admin用戶設置密碼,設置完成后就會進入登錄頁面。登錄后會直接進入儀表盤。原因是這次我們啟動Portainer時,傳遞了參數-H unix:///var/run/docker.sock,它告訴Portainer選擇我們在單機啟動Portainer時手動選擇的選項。
Swarm的不同
已經提到,在連接到Docker Swarm集群時Portainer界面會有一些變化。這一部分中會進行講解。如果某部分未有的電腦,說明與在單機模式下運行的Portainer並不分別。
端點(Endpoint)
登錄后的第一件事是選擇端點,在下面的截圖中可以看到有一個名為 primary的:
點擊該端點會進入儀表盤,我們會在這一部分的最后再次來看端點。
儀表盤和Swarm
你會注意到的第一個變化是儀表盤現在展示了Swarm集群的信息,例如:
注意CPU 處為3、總內存為3.1 GB,集群內的每個節點有1個CPU且內存為1 GB,所以這些值為集群的總和。
點擊 cluster vizualizer會進入Swarm頁面, 這里有一個集群的視覺總覽,唯一運行的服務是當前的Portainer:
棧
左側菜單中我們沒有講到的是Stacks,這里我們可以人像在Docker Swarm一章中一樣啟動棧。讓我們來拿已經使用過的Docker Compose文件為例,內容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
version: "3"
services:
redis:
image: redis:alpine
volumes:
- redis_data:/data
restart: always
mobycounter:
depends_on:
- redis
image: russmckendrick/moby-counter
ports:
- "8080:80"
restart: always
volumes:
redis_data:
|
點擊+ Add stack 按鈕,然后將上面的內容粘貼到網頁編輯器中,輸入名稱MobyCounter,不要添加空格或特殊字符,因為這個名稱Docker要使用,然后Deploy the stack按鈕。
部署完成后就可以點擊MobyCounter並管理棧:
棧是服務的集合,下面我就來看這些服務。
服務
在這個頁面你可以創建和管理服務,應該已經顯示了幾個包含Portainer在內的服務。為避免給運行中的Portainer帶來任何問題,我們創建一個新服務。中需點擊+ Add Service按鍵來進行創建。在加載的頁面中輸入如下內容:
- Name: cluster
- Image: russmckendrick/cluster
- Scheduling mode: Replicated
- Replicas : 1
這次我們需要添加一個主機8000端口與容器80端口之間的端口映射,因為我們在上一部分中所啟動的棧已占用了主機上的8080端口:
輸入宛信息后,點擊Create the service按鈕。你會回到服務列表頁面,現在應該就會包含我們剛剛添加的cluster服務了。你可能注意到在scheduling mode頁有一個scale的選項。點擊它並將我們集群服務的拷貝的數量增至6.
點擊名稱列的cluster會進入一個服務的總覽頁面。可以看到,有很多服務相關的信息:
可以對服務進行實時的修改,包括位置約束、重啟策略、添加服務標簽等等。在頁面的最底部是與服務關聯的任務列表:
可以看到,我們有6個運行中的任務,三個節點上各有兩具。點擊左側菜單中的Containers會顯示一些你可能沒預料到的信息:
只列出了三個容器,並且其中一個是Portainer服務。為什么呢?
如果你還記得Docker Swarm一章的話,我們學習了docker container命令實際上僅在運行它們的節點上進行了應用,因為Portainer是在和manager進行對話,那是docker container命令所唯一進行運行的節點。記住Portainer只是Docker API的一個網頁界面,因此它與命令行中運行 docker container ls的結果相同。
添加端點(endpoint)
但是我們可以將剩下的兩個集群節點加到Portainer中。要進行添加,點擊左側菜單的Endpoint項。
要添加端點,我們需要知道端點URL並可以訪問證書,這樣Portainer才能對運行在節點上的Docker守護進程驗證自己。所幸的是,,我們使用Docker Machine啟動的主機,這個工作非常簡單。運行如下命令來獲取端點URL:
1
|
$ docker-machine ls
|
我本機的端點 URL 是192.168.99.101:2376和192.168.99.102:2376,你的可能會不同。我們需要上傳的證書在你電腦的~/.docker/machine/certs/文件夾下。我建議運行如下命令來在finder中打開文件夾:
1
2
|
$ cd ~/.docker/machine/certs/
$ open .
|
添加了節點之后,你可以使用Settings / Endpoints頁面的+ Add Endpoint按鈕來對其進行修改。
在這填寫如下信息:
- Name: swarm-worker01
- Endpoint URL: 192.168.99.101:2376
- Public IP: 192.168.99.101
- TLS: On
- TLS with server and client verification: 勾選
- 從~/.docker/machine/certs/上傳證書
然后點擊+ Add endpoint按鍵,點擊Home會帶你進入本章這部分開頭處所見到的Endpoint總覽頁面。從下面的截圖中可以看到,worker節點分別運行了三個容器,並且它們 被標記為單機版而非 Swarm:
你會注意到除了在Endpoint中有的提及Swarm,其它地方沒有提及Swarm服務。同樣,這是因為Portainer所了解的內容和你的Docker節點一樣,Swarm模式僅允許角色為manager的節點啟動服務和任務來在集群內與其它節點交互。
別忘了通過如下命令刪除本地的Docker Swarm集群:
1
|
$ docker-machine rm swarm-manager swarm-worker01 swarm-worker02
|
總結
至此就結束Portainer的深入學習。可以看出,Portainer非常的強大,但又很容易上手,還將繼續壯大並集成更多的Docker生態系統所發布的功能。使用Portainer,你可以做大量的操作,不僅是對主機也可對單個或集群主機上運行的容器和服務。
下一章我們將在看如何保持Docker主機的安全以及如何對容器鏡像進行掃描。
課后問題
- macOS或Linux電腦上,掛載Docker套接字文件的路徑是什么?
- Portainer運行的默認端口是什么?
- 是非題:你可以使用Docker Compose文件來作為應用模板?
- 是非題:Portainer中顯示的數字僅為實時的,你無法瀏覽歷史數據?
擴展閱讀
有關Portainer的更多信息參見:
- 官網:https://portainer.io/
- Portainter的GitHub地址:https://github.com/portainer/
- 最新文檔:https://portainer.readthedocs.io/en/latest/index.html
- 模板文檔:http://portainer.readthedocs.io/en/latest/templates.html