搞事情繫列文章主要是爲了繼續延續本身的 「T」 字形戰略所作,同時也表明着畢設相關內容的學習總結。本文章是
Docker
部分的第一篇,主要是給本身解釋與Docker
有關的內容。python
原文地址:PJ 的 iOS 開發平常linux
虛擬化技術是一種將計算機物理資源進行抽象、轉換爲虛擬的計算機資源提供給程序使用的技術。這些資源包括了 CPU 提供的運算控制資源,硬盤提供的數據存儲資源,網卡提供的網絡傳輸資源等。nginx
保證程序跨平臺兼容,也就是要保證操做系統或物理硬件所提供的接口調用方式一致,程序便不須要兼容不一樣硬件平臺的接口。此時忽然想到,使用 Swift
編寫 iOS app 時,構建出包後老是會帶上 Swift
的整個運行時,以保證隨着 iOS 系統版本的升級 app 的正常運行,因其 ABI
並未穩定,還不能內置在操做系統中。git
可將虛擬化技術運用於計算機資源的管理,其中最實用的就是「虛擬內存」虛擬化技術可以提升計算機資源的使用率,是指利用虛擬化,能夠將原來程序用不到的一些資源拿出來,分享給另一些程序,讓計算機資源不被浪費。github
主要分爲兩大類:硬件虛擬化和軟件虛擬化。web
硬件虛擬化:好比假設 iOS 基於的 arm 架構 CPU 可以運行基於 x86 架構的 macOS 應用程序,這是由於 CPU 可以將另一個平臺的指令集轉換爲自身的指令集執行(但實際上並不可能)。sql
軟件虛擬化:在 2018 WWDC 中,宣佈能夠在 UIKit
層面提供一部分把 iOS app 轉移到 macOS app 中的特性,能夠理解爲是 Apple 在 Xcode 層面協助開發者構建了遷移代碼,幫開發者解決了不一樣平臺指令的轉換。也就是說,軟件虛擬化其實是經過一層夾雜在應用程序和硬件平臺上的虛擬化實現軟件來進行指令的轉換。docker
其它虛擬化技術的分類:shell
VMware
、PD
;Python
的虛擬環境;虛擬機一般說法是經過一個虛擬機監視器( Virtual Machine Monitor ) 的設施來隔離操做系統與硬件或應用程序和操做系統,以達到虛擬化的目的。這個虛擬機監視器,一般被稱爲:Hypervisor
。django
虛擬機有一個永遠都逃不掉的問題:性能低下。這種效率的低下有時候是沒法容忍的,故真實的虛擬機程序經常不徹底遵照 Hypervisor
的設計結構,而是引入一些其它技術來解決效率低下問題,好比解釋執行、即時編譯(Just In Time)運行機制,但這些技術的引入已不屬於虛擬化的範疇了。
按分類或者實現方式來講,容器技術應該屬於操做系統虛擬化,也就是在由操做系統提供虛擬化的支持。總的來講,容器技術指的是操做系統自身支持一些接口,可以讓應用程序間能夠互不干擾的獨立運行,並可以對其在運行中所使用的資源進行干預。
那這也不該該被稱爲「容器」呀?是的,這裏所謂的容器指的是因爲應用程序的運行被隔離在了一個獨立的運行環境之中,這個獨立的運行環境就好似一個容器,包裹了應用程序。
容器這麼火爆,火到一心撲在 iOS 上的我都要好好梳理一番,很重要的一個緣由是其在運行性能上遠超虛擬機等其它虛擬化實現,甚至在運行效率上與真實運行在物理平臺的應用程序不相上下。但注意,容器技術並無進行指令轉換,運行愛容器中的應用程序自身必須支持在真實操做系統上運行,也就是必須遵照硬件平臺的指令規則。
曾經看到一篇文章說 linux
內核命名空間的改進,直接推進了容器的最大化發展。
利用內核命名空間,從進程 ID 到網絡名稱,一切均可在 Linux 內核中實現虛擬化。新增的用戶命名空間「使得用戶和組 ID 能夠按命名空間進行映射。對於容器而言,這意味着用戶和組能夠在容器內部擁有執行某些操做的特權,而在容器外部則沒有這種特權。」Linux 容器項目 (LXC) 還添加了用戶亟需的一些工具、模板、庫和語言綁定,從而推進了進步,改善了使用容器的用戶體驗。LXC 使得用戶可以經過簡單的命令行界面輕鬆地啓動容器。(來源
redhat
官網)
容器因爲沒有虛擬操做系統和虛擬機監視器這兩個層次,大幅減小了應用程序帶來的額外消耗。因此在容器中的應用程序其實徹底運行在了宿主操做系統中,與其它真實運行在其中的應用程序在指令運行層面是徹底沒有任何區別的。
Docker
的核心組成能夠理解爲一個只讀的文件包,其中包含了虛擬環境運行的最原始文件系統的內容。
由於 Docker
採用 AUFS
做爲底層文件系統的實現,實現了一種增量式的鏡像結構。每次對鏡像內容修改,Docker
都會將這些修改鑄形成一個鏡像層,而一個鏡像本質上是由其下層全部的鏡像層所組成的,而每個鏡像層單獨拿出來,均可以與它之下的鏡像層組成一個鏡像。正是因爲這種結構,Docker
的鏡像本質上是沒法被修改的,由於因此的鏡像修改只會產生新的鏡像,而不是更新原有的鏡像。
在容器技術中,容器是用來隔離虛擬環境的基礎設施,但在 Docker
中,被引伸爲隔離出來的虛擬環境。若是咱們把鏡像理解爲類,則容器爲實例對象。鏡像內存放的是不可變化的東西,當以他們爲基礎的容器啓動後,容器內也就成爲類一個「活」的空間。
Docker
的容器應該有三項內容組成:
Docker
鏡像;在 Docker
中可對每一個容器進行單獨的網絡配置,也可對各個容器間創建虛擬網絡,將數個容器包裹其中,同時與其它網絡環境隔離,而且 Docker
還能在容器中構造獨立的 DNS
,咱們能夠在不修改代碼和配置的前提下直接遷移容器。
在以往的虛擬機中,大部分狀況下都直接使用虛擬機的文件系統做爲應用數據等文件的存儲位置,但並未是徹底安全的,當虛擬機或容器出現問題致使文件系統沒法使用時,雖可直接經過快速的鏡像進行重製文件系統以致於恢復,但數據也就丟失了。
爲保證數據的獨立性,一般會單獨掛在一個文件系統來存放數據,得意與 Docker
底層的 Union File System
技術,咱們能夠不用管相似於搞定掛載在不一樣宿主機中實現的方法、考慮掛載文件系統兼容性、虛擬機操做系統配置等問題。
Docker
鏡像全部的 Docker
鏡像都是按照 Docker
所設定的邏輯打包的,也是收到 Docker Engine
所控制。常見的虛擬機鏡像都是由其它用戶經過各自熟悉的方式打包成鏡像文件,公佈到網上再被其它用戶所下載後,恢復到虛擬機中的文件系統中,但 Docker
的鏡像必須經過 Docker
來打包,也必須經過 Docker
下載或導入後使用,不能單獨直接恢復成容器中的文件系統。這樣,咱們就能夠直接在服務器之間傳遞 Docker
鏡像,並配合 Docker
自身對鏡像的管理功能,使得在不一樣的機器中傳遞和共享變得很是方便。
每個記錄文件系統修改的鏡像層 Docker
都會根據它們的信息生產一個64位的 hash
碼,正是由於這個編碼,能夠可以區分不一樣的鏡像層並保證內容和編碼是一致的,咱們能夠在鏡像之間共享鏡像層。當 A
鏡像依賴了 C
鏡像,且 B
鏡像也依賴了 C
鏡像,在實際使用過程當中,A
和 B
兩個鏡像是能夠公用 C
鏡像內部的鏡像層的。
$ docker images
複製代碼
能夠分爲三部分:
Docker
對容器的設計和定義是微型容器而不是龐大臃腫的完整環境,全部一般只會在一個容器中運行一個應用程序,可以大幅下降程序之間互相的影響,利用容器技術控制每一個程序所使用的資源。在 Docker
的設計中,容器的生命週期與容器中 PID
爲 1 這個進程由密切的關係,容器的啓動本質上能夠理解爲這個進程的啓動,而容器的中止也就意味着這個進程的中止。
經過鏡像運行容器時並非當即把鏡像裏全部內容拷貝到容器所運行的沙盒文件系統中,而是利用 UnionFS
將鏡像以只讀方式掛載到沙盒文件系統中,只有在容器對文件的修改時,修改纔會體現到沙盒環境上。
docker pull ubuntu
複製代碼
docker inspect ubuntu
複製代碼
docker search django
複製代碼
docker rmi ubuntu
複製代碼
$ docker create ubuntu
複製代碼
若是咱們以前選擇的 docker pull
容器並非默認的 latest
版本,而是手動選擇了一個版本,那鏡像的名字將會好比 nginx:1.12
,對於後續的操做都十分的不方便,對此,咱們能夠採用 --name
進行重命名:
$ docker create --name nginx nginx:1.12
複製代碼
$ docker start ubuntu
複製代碼
經過 docker run
可將上述兩個命令進行合併:
$ docker run --name nginx nginx:1.12
複製代碼
以上命令跑起來的容器運行都是運行在前臺,若是咱們想要容器運行在後臺,能夠經過 -d
,其是 -detach
的簡稱,告訴 Docker
在啓動後將程序和控制進行分離。:
$ docker run -d ubuntu
複製代碼
列出運行中的全部容器
$ docker ps
複製代碼
列出全部容器
$ docker ps -a/-all
複製代碼
其中打印出的列表須要注意的是 STATUS 字段,常見的狀態表示有三種:
$ docker stop ubuntu
複製代碼
容器中止後,其維持的文件系統沙盒環境會一直保存,內部被修改的內容也會被保留。經過 docker start
將容器繼續啓動。
當須要把容器徹底刪除容器,可使用:
$ docker rm ubuntu
複製代碼
但在運行中的容器默認狀況下是不能被刪除的,但咱們能夠經過如下命令進行刪除:
$ docker rm -f ubuntu
複製代碼
Docker
與其它虛擬機不一樣,其所定位的輕量級設計講究隨用隨開,隨關隨刪,當咱們短期內不須要使用容器時,最佳的作法是刪除它而不是僅僅中止它。
若是咱們要對程序作一些環境配置,徹底能夠直接將這些配置打包至一個新的鏡像中,下次直接使用該鏡像建立容器便可。對於一些重要的文件資料,不能隨着容器的刪除而刪除,可使用 Docker
中的數據卷來單獨存放。
$ docker run -it --name ubuntu ubuntu
複製代碼
$ docker exec -it ubuntu /bin/bash
複製代碼
-i
表示保持咱們的輸入流;-t
表示啓用一個僞終端,造成咱們與 bash 的交互。當容器運行在後臺,想要在將當前的輸入輸出流鏈接到指定的容器上,能夠這麼作:
$ docker attach ubuntu
複製代碼
經過 docker attach
啓動的容器,能夠理解爲與 docker run -d
作了相反的事情,把當前容器從後臺拉回了前臺。
在 Docker
網絡中,有三個比較核心的概念,造成了 Docker
的網絡核心模型,即容器網絡模型(Container Network Model):
IP
路由表、防火牆等;Docker
內部的虛擬子網,網絡內的參與者相互可見並可以進行通信。須要注意的是,這種虛擬網絡與宿主機存在隔離關係。Docker
的網絡實現目前官方提供了五種網絡驅動:
Docker
的集羣模塊 Docker Swarm
來搭建的跨 Docker Daemon
網絡,能夠經過它搭建跨物理主機的虛擬網絡,從而讓不一樣物理機中運行的容器感知不到多個物理機的存在。網絡剩餘內容將在下篇文章中繼續進行......
學習到這裏後,開始對 Docker
所謂「輕量級」的主打理念有了一個初步的認識,準備利用 Docker
的這一特性作一個 Swift
編譯服務,主要想利用 Vapor
/Perfect
(這兩個到底選哪個還需調研)來搭建 HTTP 服務,接收傳入的代碼文本,執行並返回結果。
思考了一下,須要:
Swift
能力的 Docker
鏡像;Vapor
/Perfect
框架的 Docker
鏡像;Nginx
web 服務器的 Docker
鏡像;這一套下來後,將從新發佈一個「開箱即用」的提供 Swift
編譯服務的 Docker
鏡像~想一想就是個很是美好的事情呢!接下來開始第一步
Swift
能力的 Docker
鏡像以前有看到的文章說直接能夠在 Ubuntu
上構建本身的 Swift
版本,因此個人第一步先去找一個 Ubuntu
鏡像,這點很是容易:
$ docker pull ubuntu
$ docker run -it --name ubuntu ubuntu /bin/bash 複製代碼
成功進入到 bash 後,繼續下一步。找到一個萬能命令,根據這個命令能夠先把編譯 Swift
須要的相關依賴都下載完成:
sudo apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config
複製代碼
接着,下載 Swift
源碼:
git clone https://github.com/apple/swift.git
複製代碼
再下載項目依賴的其它源碼:
./utils/update-checkout --clone
複製代碼
完成後,便可開始利用源碼中的工具進行編譯和測試!
utils/build-script -t
複製代碼
此處將會經歷漫長的等待。二十分鐘後,我獲得了兩個報錯:
clang: error: unable to execute command: Killed
clang: error: linker command failed due to signal (use -v to see invocation)
ninja: build stopped: subcommand failed.
utils/build-script: fatal error: command terminated with a non-zero exit status 1, aborting
複製代碼
clang: error: unable to execute command: Killed
clang: error: linker command failed due to signal (use -v to see invocation)
[1747/3019] Linking CXX shared library lib/libLTO.so.7svn
FAILED: lib/libLTO.so.7svn
複製代碼
看提示是一些依賴庫出了問題,剛開始覺得更新下對應的依賴庫就完事了,沒想到在網上竟然找到不對應的報錯提示!這對於第一次手動編譯 Swift
的玩家來講十分的不友好,折騰了一下子後放棄!
此時,又看到一篇文章有說能夠直接利用 Swift
官網已經構建完成的二進制文件進行使用,地址在此 swift.org/download/ ,在 Docker
中能夠經過 wget
進行下載。但因未找到 Swift 4.2.1
的正確下載地址,而且也擔憂直接修改以往版本下載地址進行猜想地址不對,在宿主機上下載完成後,經過 docker cp /path dockerContainer:/path
命令把文件夾傳遞到了容器中。
在添加 PATH
我又遇到了以下錯誤:
swift: error while loading shared libraries: libatomic.so.1: cannot open shared object file: No such file or directory
複製代碼
swift: error while loading shared libraries: libedit.so.2: cannot open shared object file: No such file or directory
複製代碼
幾乎已經把 SO 上全部的解決方案進行了嘗試,皆無果,有 issue
說估計是 Docker 自己的問題,折騰了好一下子,遂放棄。
當時覺得這已是最後一種方案,因此折騰了特別久,沒想到其實 Apple 官方竟然維護了一套 swift-docker
,開箱即用,特別香!!!
$ docker pull swift
$ docker run --privileged -i -t --name swiftfun swift:latest /bin/bash
複製代碼
至此,第一步已經完成!這回都省去了本身構建鏡像的工做了~