我最近在我的一個業餘項目中遇到了挑戰。我需要将在一台機器上建構的docker容器轉移到另一台可以通過SSH通路的機器上。我不想将我的容器推送到公共docker系統資料庫,也不想設定自己的私有系統資料庫。
使用内置工具
很快就在stack overflow找到了答案(https://stackoverflow.com/a/26226261/272958)
docker save | bzip2 | ssh [email protected] 'bunzip2 | docker load'
讓我們分解一下:
- docker save 擷取所有圖像資料,并将其及其标簽序列化為二進制資料流。
- docker load 接收二進制資料流并将其反序列化為帶有标簽的圖像。
- bzip2壓縮流并bunzip2解壓縮流。
- ssh [email protected] 'some command' ssh進入遠端主機并運作指定的指令。
事實證明,docker load它能夠自動解壓縮bzip'd内容,是以您可以将指令簡化為:
docker save | bzip2 | ssh [email protected] 'docker load'
您可以删除,bzip2但是docker映像通常很大,從進行壓縮bzip2可以節省大量帶寬。
我仍然有一個問題。我通過慢速的3G Internet連接配接進行所有操作,并且遠端主機已經具有要推送的映像中的大多數層,我隻需要推送包含我的應用程式邏輯的微小新層即可。
Pushing With Layers
經過更多研究,我發現docker-push-ssh。使用此指令,您可以執行以下操作:
docker-push-ssh [email protected]
它僅傳輸所需的層。為此:
- 在本地計算機上設定一個臨時Docker系統資料庫-這很容易做到,因為在名為docker的鏡像中有一個docker系統資料庫 registry:2
- 難道一個docker push到本地系統資料庫。因為它遍及本地計算機的網絡,是以速度很快。
- 使用SSH代理遠端伺服器上的端口,以便它連接配接到本地計算機上的代理。
- 難道一個docker pull遠端伺服器上。該拉取在SSH隧道上運作,但是docker pull非常聰明,僅拉取它尚不具備的層。
我自己的解決方案
這是一個好主意,但是我遇到了三個問題:
- 它是用Python編寫的,并且需要Python 2.7,我不想依賴于已安裝。
- 它已經有一段時間沒有更新了,通常不會有什麼問題,但是考慮到它依賴于舊版本的Python,這有點令人擔憂。
- 目前尚不清楚遠端計算機上所需的特權級别。我希望能夠将事情鎖定下來,以便進行推送的使用者隻能将特定的已命名docker映像推送到遠端計算機,而不能做其他任何事情。
為了解決所有這些問題,我決定在Node.js中建立一個名為docker-over-ssh的CLI 。盡管名稱如此,但docker-over-ssh實際上完全與傳輸無關。它僅需要一種通過stdin和stdout與自身的遠端執行個體進行通信的方法。要使用它,請docker-over-ssh同時在本地和遠端計算機上安裝。然後,您可以運作:
docker-over-ssh push ssh [email protected] "docker-over-ssh pull "
該圖看起來與先前的解決方案完全相同。
該docker-over-ssh push指令将啟動本地docker系統資料庫,将映像推送到其中,然後運作“子指令”(在本示例中為ssh [email protected] "docker-over-ssh pull "),并将tcp流量從該子指令的stdio代理到本地docker系統資料庫。
該docker-over-ssh pull 指令啟動一個本地TCP代理(用幾行node.js代碼編寫),并将該代理連接配接到stdio,以便它可以與本地docker系統資料庫通信。然後,它docker pull指向本地系統資料庫運作。僅傳輸新的層,進而使所有工作保持高效。
使用者唯一需要的許可是docker-over-ssh pull 在遠端計算機上運作的能力,而無需任何其他操作。
與CircleCI一起使用
在這一點上,我有一個可行的解決方案,但是我想使它自動化,以便可以從CircleCI進行部署。向CircleCI添加SSH密鑰非常容易。面臨的挑戰是如何通過其複雜的docker網絡設定來完成這項工作:
- 您的本地代碼(即終止代理的node.js代碼)無法與使用運作的容器對話docker run。
- 該docker守護程序(用于運作docker push)不能跟跑為主要CircleCI工作服務容器。
我找不到直接解決這兩個問題的任何實用方法,但是我發現NGROK可以很容易地建立一個可以通路本地服務的Internet通路位址。有了這個,我能夠告訴CircleCI啟動Docker系統資料庫作為建構服務,然後使用ngrok啟動一個臨時代理以将其公開給docker守護程式。它甚至支援使用使用者名和密碼(由我自動生成)來保護它,以確定一切安全。
最後,我要做的就是更新CircleCI配置:
docker: - image: circleci/node:12 environment: LOCAL_DOCKER_REGISTRY_PORT: '5000' - image: registry:2
并将DOCKER_REGISTRY_NGROK環境變量設定為我的ngrok API密鑰,您可以免費擷取。
然後,我向docker-over-ssh添加了一些代碼來處理這兩個環境變量。
結論
我做所有這些事情的原因是嘗試安裝一個dokku伺服器,我可以在其中運作很多輔助項目,并避免在heroku上花費很少的金錢來處理很少使用的東西。我對這個問題的解決方案感到非常滿意,但是由于Digital Ocean擁有托管的Kubernetes服務,而且價格似乎非常實惠,是以我現在決定研究Kubernetes 。這将需要我弄清楚運作具有某種身份驗證/授權的持久性Docker系統資料庫。
翻譯自:https://itnext.io/docker-over-ssh-51ab25a79f2e