從頭認識一下docker-附帶asp.net core程式的docker化部署

来源:https://www.cnblogs.com/gdsblog/archive/2019/01/25/10321595.html
-Advertisement-
Play Games

從頭認識一下docker-附帶asp.net core程式的docker化部署 ...


從頭認識一下docker-附帶asp.net core程式的docker化部署

簡介

在電腦技術日新月異的今天, Docker 在國內發展的如火如荼,特別是在一線互聯網公司, Docker 的使用是十分普遍的。
編寫此套教程,來帶大家去瞭解並熟練運用 docker ,祝願各位讀者朋友們學完此套教程後,在未來企業面試中能夠多一項加分的籌碼,能夠幫助到大家,我覺得就很值了。

docker 是什麼

既然說了這麼多, docker 到底是個什麼東西呢?

我們在理解 docker 之前,首先我們得先區分清楚兩個概念,容器和虛擬機。

可能很多讀者朋友都用過虛擬機,而對容器這個概念比較的陌生。

我們用的傳統虛擬機如 VMware , VisualBox 之類的需要模擬整台機器包括硬體,每台虛擬機都需要有自己的操作系統,虛擬機一旦被開啟,預分配給它的資源將全部被占用。每一臺虛擬機包括應用,必要的二進位和庫,以及一個完整的用戶操作系統。

而容器技術是和我們的宿主機共用硬體資源及操作系統,可以實現資源的動態分配。容器包含應用和其所有的依賴包,但是與其他容器共用內核。容器在宿主機操作系統中,占用用戶空間以分離的進程運行。

容器技術是實現操作系統虛擬化的一種途徑,可以讓您在資源受到隔離的進程中運行應用程式及其依賴關係。通過使用容器,我們可以輕鬆打包應用程式的代碼、配置和依賴關係,將其變成容易使用的構建塊,從而實現環境一致性、運營效率、開發人員生產力和版本控制等諸多目標。容器可以幫助保證應用程式快速、可靠、一致地部署,其間不受部署環境的影響。容器還賦予我們對資源更多的精細化控制能力,讓我們的基礎設施效率更高。通過下麵這幅圖我們可以很直觀的反映出這兩者的區別所在

Docker 屬於 Linux 容器的一種封裝,提供簡單易用的容器使用介面。它是目前最流行的 Linux 容器解決方案。

而 Linux 容器是 Linux 發展出了另一種虛擬化技術,簡單來講, Linux 容器不是模擬一個完整的操作系統,而是對進程進行隔離,相當於是在正常進程的外面套了一個保護層。對於容器裡面的進程來說,它接觸到的各種資源都是虛擬的,從而實現與底層系統的隔離。

Docker 將應用程式與該程式的依賴,打包在一個文件裡面。運行這個文件,就會生成一個虛擬容器。程式在這個虛擬容器里運行,就好像在真實的物理機上運行一樣。有了 Docker ,就不用擔心環境問題。

總體來說, Docker 的介面相當簡單,用戶可以方便地創建和使用容器,把自己的應用放入容器。容器還可以進行版本管理、複製、分享、修改,就像管理普通的代碼一樣。

Docker的優勢

Docker相比於傳統虛擬化方式具有更多的優勢:

  1. docker 啟動快速屬於秒級別。虛擬機通常需要幾分鐘去啟動
  2. docker 需要的資源更少, docker 在操作系統級別進行虛擬化, docker 容器和內核交互,幾乎沒有性能損耗,性能優於通過 Hypervisor 層與內核層的虛擬化
  3. docker 更輕量, docker 的架構可以共用一個內核與共用應用程式庫,所占記憶體極小。同樣的硬體環境, Docker 運行的鏡像數遠多於虛擬機數量,對系統的利用率非常高
  4. 與虛擬機相比, docker 隔離性更弱, docker 屬於進程之間的隔離,虛擬機可實現系統級別隔離
  5. 安全性: docker 的安全性也更弱。 Docker 的租戶 root 和宿主機 root 等同,一旦容器內的用戶從普通用戶許可權提升為root許可權,它就直接具備了宿主機的root許可權,進而可進行無限制的操作。虛擬機租戶 root 許可權和宿主機的 root 虛擬機許可權是分離的,並且虛擬機利用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬體隔離技術,這種隔離技術可以防止虛擬機突破和彼此交互,而容器至今還沒有任何形式的硬體隔離,這使得容器容易受到攻擊
  6. 可管理性: docker 的集中化管理工具還不算成熟。各種虛擬化技術都有成熟的管理工具,例如 VMware vCenter 提供完備的虛擬機管理能力
  7. 高可用和可恢復性: docker 對業務的高可用支持是通過快速重新部署實現的。虛擬化具備負載均衡,高可用,容錯,遷移和數據保護等經過生產實踐檢驗的成熟保障機制, VMware 可承諾虛擬機 99.999% 高可用,保證業務連續性
  8. 快速創建、刪除:虛擬化創建是分鐘級別的, Docker 容器創建是秒級別的, Docker 的快速迭代性,決定了無論是開發、測試、部署都可以節約大量時間
  9. 交付、部署:虛擬機可以通過鏡像實現環境交付的一致性,但鏡像分發無法體系化。 Docker 在 Dockerfile 中記錄了容器構建過程,可在集群中實現快速分發和快速部署

docker 的三個基本概念

從上圖我們可以看到,Docker 中包括三個基本的概念:

  1. Image(鏡像)
  2. Container(容器)
  3. Repository(倉庫)

鏡像是 Docker 運行容器的前提,倉庫是存放鏡像的場所,可見鏡像更是 Docker 的核心。

Image (鏡像)

那麼鏡像到底是什麼呢?

Docker 鏡像可以看作是一個特殊的文件系統,除了提供容器運行時所需的程式、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如匿名捲、環境變數、用戶等)。鏡像不包含任何動態數據,其內容在構建之後也不會被改變。

鏡像(Image)就是一堆只讀層(read-only layer)的統一視角,也許這個定義有些難以理解,下麵的這張圖能夠幫助讀者理解鏡像的定義。

從左邊我們看到了多個只讀層,它們重疊在一起。除了最下麵一層,其它層都會有一個指針指向下一層。這些層是Docker 內部的實現細節,並且能夠在主機的文件系統上訪問到。統一文件系統 (union file system) 技術能夠將不同的層整合成一個文件系統,為這些層提供了一個統一的視角,這樣就隱藏了多層的存在,在用戶的角度看來,只存在一個文件系統。我們可以在圖片的右邊看到這個視角的形式。

Container (容器)

容器 (container) 的定義和鏡像 (image) 幾乎一模一樣,也是一堆層的統一視角,唯一區別在於容器的最上面那一層是可讀可寫的。

由於容器的定義並沒有提及是否要運行容器,所以實際上,容器 = 鏡像 + 讀寫層。

Repository (倉庫)

Docker 倉庫是集中存放鏡像文件的場所。鏡像構建完成後,可以很容易的在當前宿主上運行,但是, 如果需要在其它伺服器上使用這個鏡像,我們就需要一個集中的存儲、分發鏡像的服務,Docker Registry (倉庫註冊伺服器)就是這樣的服務。有時候會把倉庫 (Repository) 和倉庫註冊伺服器 (Registry) 混為一談,並不嚴格區分。Docker 倉庫的概念跟 Git 類似,註冊伺服器可以理解為 GitHub 這樣的托管服務。實際上,一個 Docker Registry 中可以包含多個倉庫 (Repository) ,每個倉庫可以包含多個標簽 (Tag),每個標簽對應著一個鏡像。所以說,鏡像倉庫是 Docker 用來集中存放鏡像文件的地方類似於我們之前常用的代碼倉庫。

通常,一個倉庫會包含同一個軟體不同版本的鏡像,而標簽就常用於對應該軟體的各個版本 。我們可以通過<倉庫名>:<標簽>的格式來指定具體是這個軟體哪個版本的鏡像。如果不給出標簽,將以 latest 作為預設標簽.。

倉庫又可以分為兩種形式:

  1. public(公有倉庫)
  2. private(私有倉庫)

Docker Registry 公有倉庫是開放給用戶使用、允許用戶管理鏡像的 Registry 服務。一般這類公開服務允許用戶免費上傳、下載公開的鏡像,並可能提供收費服務供用戶管理私有鏡像。

除了使用公開服務外,用戶還可以在本地搭建私有 Docker Registry 。Docker 官方提供了 Docker Registry 鏡像,可以直接使用做為私有 Registry 服務。當用戶創建了自己的鏡像之後就可以使用 push 命令將它上傳到公有或者私有倉庫,這樣下次在另外一臺機器上使用這個鏡像時候,只需要從倉庫上 pull 下來就可以了。

我們主要把 Docker 的一些常見概念如 Image , Container , Repository 做了詳細的闡述,也從傳統虛擬化方式的角度闡述了 docker 的優勢,我們從下圖可以直觀地看到 Docker 的架構:

Docker 使用 C/S 結構,即客戶端/伺服器體繫結構。 Docker 客戶端與 Docker 伺服器進行交互,Docker服務端負責構建、運行和分發 Docker 鏡像。 Docker 客戶端和服務端可以運行在一臺機器上,也可以通過 RESTful 、 stock 或網路介面與遠程 Docker 服務端進行通信。

Docker的安裝和使用

Docker 的安裝和使用有一些前提條件,主要體現在體系架構和內核的支持上。對於體系架構,除了 Docker 一開始就支持的 X86-64 ,其他體系架構的支持則一直在不斷地完善和推進中。

Docker 分為 CE 和 EE 兩大版本。 CE 即社區版(免費,支持周期 7 個月), EE 即企業版,強調安全,付費使用,支持周期 24 個月。

我們在安裝前可以參看官方文檔獲取最新的 Docker 支持情況,官方文檔在這裡

https://docs.docker.com/install/

Docker 對於內核支持的功能,即內核的配置選項也有一定的要求(比如必須開啟 Cgroup 和 Namespace 相關選項,以及其他的網路和存儲驅動等), Docker 源碼中提供了一個檢測腳本來檢測和指導內核的配置,腳本鏈接在這裡:

https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh

在滿足前提條件後,安裝就變得非常的簡單了。

Docker CE 的安裝請參考官方文檔:

  1. MacOS:https://docs.docker.com/docker-for-mac/install/
  2. Windows:https://docs.docker.com/docker-for-windows/install/
  3. Ubuntu:https://docs.docker.com/install/linux/docker-ce/ubuntu/
  4. Debian:https://docs.docker.com/install/linux/docker-ce/debian/
  5. CentOS:https://docs.docker.com/install/linux/docker-ce/centos/
  6. Fedora:https://docs.docker.com/install/linux/docker-ce/fedora/
  7. 其他 Linux 發行版:https://docs.docker.com/install/linux/docker-ce/binaries/

這裡我們以 CentOS7 作為本文的演示。

環境準備

  1. 阿裡雲伺服器(1核2G,1M帶寬)

  2. CentOS 7.4 64位

卸載舊版本

由於 Docker-CE 支持 64 位版本的 CentOS7 ,並且要求內核版本不低於 3.10

首先我們需要卸載掉舊版本的 Docker,如果你之前未安裝過,可以跳過此步驟

$ sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine

安裝

  1. 我們執行以下安裝命令去安裝依賴包:
$ sudo yum install -y yum-utils \
           device-mapper-persistent-data \
           lvm2

  1. 安裝Docker

Docker 軟體包已經包括在預設的 CentOS-Extras 軟體源里。因此想要安裝 docker,只需要運行下麵的 yum 命令

$ sudo yum install docker

當然在測試或開發環境中 Docker 官方為了簡化安裝流程,提供了一套便捷的安裝腳本,CentOS 系統上可以使用這套腳本安裝:

curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh

具體可以參看 docker-install 的腳本:

https://github.com/docker/docker-install

執行這個命令後,腳本就會自動的將一切準備工作做好,並且把 Docker CE 的 Edge 版本安裝在系統中。

安裝過程中可能會出現這個問題,Delta RPMs disabled because /usr/bin/applydeltarpm not installed.

這時應該是我們伺服器還確實依賴包,執行一下命令安裝

yum provides '*/applydeltarpm'

yum install deltarpm

然後重新執行

curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh

安裝過程鐘可能出現另一個問題,No Presto metadata available for docker-ce-edge No Presto metadata available for base

在網上查到原因:由於國內訪問不到docker官方鏡像的緣故

可以通過aliyun的源來完成,做如下操作問題解決:yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

然後重新執行

curl -fsSL get.docker.com -o get-docker.sh
sh get-docker.sh

安裝完成後,運行下麵的命令,驗證是否安裝成功:


docker version
or
docker info

  1. 啟動Docker-CE

$ sudo systemctl enable docker

$ sudo systemctl start docker

Docker的簡單運用---Hello World

我們通過最簡單的 image 文件 hello world,感受一下 Docker 的魅力吧!

我們直接運行下麵的命令,將名為 hello-world 的 image 文件從倉庫抓取到本地。

docker pull library/hello-world
docker pull images 是抓取 image 文件, library/hello-world 是 image 文件在倉庫裡面的位置,其中 library 是 image 文件所在的組, hello-world 是 image 文件的名字。

抓取成功以後,就可以在本機看到這個 image 文件了。

docker images

我們可以看到如下結果:

現在,我們可以運行 hello-world 這個 image 文件

docker run hello-world

輸出這段提示以後,hello world 就會停止運行,容器自動終止。有些容器不會自動終止,因為提供的是服務,比如Mysql鏡像等。

是不是很容易呢?我們從上面可以看出, docker 的功能是十分強大的,除此之外,我們還可以拉去一些 Ubuntu , Apache 等鏡像。

Docker 提供了一套簡單實用的命令來創建和更新鏡像,我們可以通過網路直接下載一個已經創建好了的應用鏡像,並通過 Docker RUN 命令就可以直接使用。當鏡像通過 RUN 命令運行成功後,這個運行的鏡像就是一個 Docker 容器啦,容器可以理解為一個輕量級的沙箱, Docker 利用容器來運行和隔離應用,容器是可以被啟動、停止、刪除的,這並不會影響 Docker 鏡像。

我們可以看看下麵這幅圖:

Docker 客戶端是 Docker 用戶與 Docker 交互的主要方式。當您使用 docker 命令行運行命令時, Docker 客戶端將這些命令發送給伺服器端,服務端將執行這些命令。 docker 命令使用 docker API 。 Docker 客戶端可以與多個服務端進行通信。

我們將剖析一下 Docker 容器是如何工作的,學習好Docker容器工作的原理,我們就可以自己去管理我們的容器了。

Docker架構

在上面的學習中,我們簡單地講解了Docker的基本架構。瞭解到了Docker 使用的是 C/S 結構,即客戶端/伺服器體繫結構。明白了 Docker 客戶端與 Docker 伺服器進行交互時, Docker 服務端負責構建、運行和分發 Docker 鏡像。 也知道了Docker 客戶端和服務端可以運行在一臺機器上,可以通過 RESTful 、 stock 或網路介面與遠程 Docker 服務端進行通信。

我們從下圖可以很直觀的瞭解到Docker的架構:

Docker 的核心組件包括:

  1. Docker Client
  2. Docker daemon
  3. Docker Image
  4. Docker Registry
  5. Docker Container

Docker 採用的是 Client/Server 架構。客戶端向伺服器發送請求,伺服器負責構建、運行和分發容器。客戶端和伺服器可以運行在同一個 Host 上,客戶端也可以通過 socket 或 REST API 與遠程的伺服器通信。

Docker Client

Docker Client ,也稱 Docker 客戶端。它其實就是 Docker 提供命令行界面 (CLI) 工具,是許多 Docker 用戶與 Docker 進行交互的主要方式。客戶端可以構建,運行和停止應用程式,還可以遠程與Docker_Host進行交互。最常用的 Docker 客戶端就是 docker 命令,我們可以通過 docker 命令很方便地在 host 上構建和運行 docker 容器。

Docker daemon

Docker daemon 是伺服器組件,以 Linux 後臺服務的方式運行,是 Docker 最核心的後臺進程,我們也把它稱為守護進程。它負責響應來自 Docker Client 的請求,然後將這些請求翻譯成系統調用完成容器管理操作。該進程會在後臺啟動一個 API Server ,負責接收由 Docker Client 發送的請求,接收到的請求將通過Docker daemon 內部的一個路由分發調度,由具體的函數來執行請求。

我們大致可以將其分為以下三部分:

  1. Docker Server
  2. Engine
  3. Job

Docker Daemon的架構如下所示:

Docker Daemon 可以認為是通過 Docker Server 模塊接受 Docker Client 的請求,併在 Engine 中處理請求,然後根據請求類型,創建出指定的 Job 並運行。 Docker Daemon 運行在 Docker host 上,負責創建、運行、監控容器,構建、存儲鏡像。

運行過程的作用有以下幾種可能:

  1. 向 Docker Registry 獲取鏡像
  2. 通過 graphdriver 執行容器鏡像的本地化操作
  3. 通過 networkdriver 執行容器網路環境的配置
  4. 通過 execdriver 執行容器內部運行的執行工作
  5. 由於 Docker Daemon 和 Docker Client 的啟動都是通過可執行文件 docker 來完成的,因此兩者的啟動流程非常相似。 Docker 可執行文件運行時,運行代碼通過不同的命令行 flag 參數,區分兩者,並最終運行兩者各自相應的部分。

啟動 Docker Daemon 時,一般可以使用以下命令來完成


docker --daemon = true
docker –d
docker –d = true

再由 docker 的 main() 函數來解析以上命令的相應 flag 參數,並最終完成 Docker Daemon 的啟動。

下圖可以很直觀地看到 Docker Daemon 的啟動流程:

預設配置下, Docker daemon 只能響應來自本地 Host 的客戶端請求。如果要允許遠程客戶端請求,需要在配置文件中打開 TCP 監聽。我們可以照著如下步驟進行配置:

  1. 編輯配置文件 /etc/systemd/system/multi-user.target.wants/docker.service ,在環境變數 ExecStart 後面添加 -H tcp://0.0.0.0,允許來自任意 IP 的客戶端連接。

  1. 重啟 Docker daemon

systemctl daemon-reload
systemctl restart docker.service

  1. 我們通過以下命令即可實現與遠程伺服器通信

docker -H 伺服器IP地址 info

-H 是用來指定伺服器主機, info 子命令用於查看 Docker 伺服器的信息

Docker Image

Docker 鏡像可以看作是一個特殊的文件系統,除了提供容器運行時所需的程式、庫、資源、配置等文件外,還包含了一些為運行時準備的一些配置參數(如匿名捲、環境變數、用戶等)。鏡像不包含任何動態數據,其內容在構建之後也不會被改變。我們可將 Docker 鏡像看成只讀模板,通過它可以創建 Docker 容器。

鏡像有多種生成方法:

  1. 從無到有開始創建鏡像
  2. 下載並使用別人創建好的現成的鏡像
  3. 在現有鏡像上創建新的鏡像

我們可以將鏡像的內容和創建步驟描述在一個文本文件中,這個文件被稱作 Dockerfile ,通過執行 docker build 命令可以構建出 Docker 鏡像。

Docker Registry

Docker registry 是存儲 docker image 的倉庫,它在 docker 生態環境中的位置如下圖所示:

運行docker push、docker pull、docker search時,實際上是通過 docker daemon 與 docker registry 通信。

Docker Container

Docker 容器就是 Docker 鏡像的運行實例,是真正運行項目程式、消耗系統資源、提供服務的地方。 Docker Container 提供了系統硬體環境,我們可以使用 Docker Images 這些製作好的系統盤,再加上我們所編寫好的項目代碼, run 一下就可以提供服務啦。

Docker組件是如何協作運行容器

看到這裡,我相信各位讀者朋友們應該已經對Docker基礎架構已經熟悉的差不多了,我們還記得運行的第一個容器嗎?現在我們再通過hello-world這個例子來體會一下 Docker 各個組件是如何協作的。

容器啟動過程如下:

  1. Docker 客戶端執行 docker run 命令

  2. Docker daemon 發現本地沒有 hello-world 鏡像

  3. daemon 從 Docker Hub 下載鏡像

  4. 下載完成,鏡像 hello-world 被保存到本地

  5. Docker daemon 啟動容器

具體過程可以看如下這幅演示圖:

我們可以通過docker images 可以查看到 hello-world 已經下載到本地。

我們可以通過docker ps 或者 docker container ls 顯示正在運行的容器,我們可以看到, hello-world 在輸出提示信息以後就會停止運行,容器自動終止,所以我們在查看的時候沒有發現有容器在運行。

我們把 Docker 容器的工作流程剖析的十分清楚了,我們大體可以知道 Docker 組件協作運行容器可以分為以下幾個過程:

  1. Docker 客戶端執行 docker run 命令
  2. Docker daemon 發現本地沒有我們需要的鏡像
  3. daemon 從 Docker Hub 下載鏡像
  4. 下載完成後,鏡像被保存到本地
  5. Docker daemon 啟動容器

瞭解了這些過程以後,我們再來理解這些命令就不會覺得很突兀了,下麵我們看一下 Docker 常用的一些命令操作吧。

Docker常用命令

我們可以通過 docker -h 去查看命令的詳細的幫助文檔。在這裡我只會講一些平常日常比賽或者生活中我們可能會用的比較多的一些命令

例如,我們需要拉取一個 docker 鏡像,我們可以用如下命令:

docker pull image_name

image_name 為鏡像的名稱,而如果我們想從 Docker Hub 上去下載某個鏡像,我們可以使用以下命令:

docker pull centos:latest

centos:lastest 是鏡像的名稱, Docker daemon 發現本地沒有我們需要的鏡像,會自動去 Docker Hub 上去下載鏡像,下載完成後,該鏡像被預設保存到 /var/lib/docker 目錄下。

接著我們如果想查看下主機下存在多少鏡像,我們可以用如下命令:

docker images

我們要想知道當前有哪些容器在運行,我們可以用如下命令:

docker ps -a

-a 是查看當前所有的容器,包括未運行的

我們該如何去對一個容器進行啟動,重啟和停止呢?我們可以用如下命令:

docker start container_name/container_id
docker restart container_name/container_id
docker stop container_name/container_id

這個時候我們如果想進入到這個容器中,我們可以使用 attach 命令:

docker attach container_name/container_id

那如果我們想運行這個容器中的鏡像的話,並且調用鏡像裡面的 bash ,我們可以使用如下命令:

cdocker run -t -i container_name/container_id /bin/bash

那如果這個時候,我們想刪除指定鏡像的話,由於 image 被某個 container 引用(拿來運行),如果不將這個引用的 container 銷毀(刪除),那 image 肯定是不能被刪除。我們首先得先去停止這個容器:

docker ps

docker stop container_name/container_id

然後我們用如下命令去刪除這個容器:

docker rm container_name/container_id

然後這個時候我們再去刪除這個鏡像:

docker rmi image_name

此時,常用的 Docker 相關的命令就講到這裡為止了。

Dockerfile是什麼

前面我們已經提到了 Docker 的一些基本概念。我們可以去使用 Dockerfile 定義鏡像,依賴鏡像來運行容器,可以去模擬出一個真實的漏洞場景。因此毫無疑問的說, Dockerfile 是鏡像和容器的關鍵,並且 Dockerfile 還可以很輕易的去定義鏡像內容,說了這麼多,那麼 Dockerfile 到底是個什麼東西呢?

Dockerfile 是自動構建 docker 鏡像的配置文件, 用戶可以使用 Dockerfile 快速創建自定義的鏡像。Dockerfile 中的命令非常類似於 linux 下的 shell 命令。

我們可以通過下麵這幅圖來直觀地感受下 Docker 鏡像、容器和 Dockerfile 三者之間的關係。

我們從上圖中可以看到, Dockerfile 可以自定義鏡像,通過 Docker 命令去運行鏡像,從而達到啟動容器的目的。

Dockerfile 是由一行行命令語句組成,並且支持已 # 開頭的註釋行。

一般來說,我們可以將 Dockerfile 分為四個部分:

  1. 基礎鏡像(父鏡像)信息指令 FROM
  2. 維護者信息指令 MAINTAINER
  3. 鏡像操作指令 RUN 、 EVN 、 ADD 和 WORKDIR 等
  4. 容器啟動指令 CMD 、 ENTRYPOINT 和 USER 等

下麵是一段簡單的Dockerfile的例子(也可以看下文的asp.net core 的dockerfile配置文件):

FROM python:2.7
MAINTAINER Angel_Kitty <[email protected]>
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT ["python"]
CMD ["app.py"]

我們可以分析一下上面這個過程:

  1. 從 Docker Hub 上 pull 下 python 2.7 的基礎鏡像
  2. 顯示維護者的信息
  3. copy 當前目錄到容器中的 /app 目錄下 複製本地主機的 ( Dockerfile 所在目錄的相對路徑)到容器里
  4. 指定工作路徑為 /app
  5. 安裝依賴包
  6. 暴露 5000 埠
  7. 啟動 app

這個例子是啟動一個 python flask app 的 Dockerfile ( flask 是 python 的一個輕量的 web 框架),相信大家從這個例子中能夠稍微理解了Dockfile的組成以及指令的編寫過程。

Dockerfile常用的指令

根據上面的例子,我們已經差不多知道了Dockerfile的組成以及指令的編寫過程,我們再來理解一下這些常用命令就會得心應手了。

由於 Dockerfile 中所有的命令都是以下格式:INSTRUCTION argument ,指令 (INSTRUCTION) 不分大小寫,但是推薦大寫。

FROM
FROM 是用於指定基礎的 images ,一般格式為 FROM or FORM : ,所有的 Dockerfile 都用該以 FROM 開頭,FROM 命令指明 Dockerfile 所創建的鏡像文件以什麼鏡像為基礎,FROM 以後的所有指令都會在 FROM 的基礎上進行創建鏡像。可以在同一個 Dockerfile 中多次使用 FROM 命令用於創建多個鏡像。比如我們要指定 python 2.7 的基礎鏡像,我們可以像如下寫法一樣:

FROM python:2.7

MAINTAINER

MAINTAINER 是用於指定鏡像創建者和聯繫方式,一般格式為 MAINTAINER 。這裡我設置成我的 ID 和郵箱:

MAINTAINER Angel_Kitty [email protected]

COPY

COPY 是用於複製本地主機的 (為 Dockerfile 所在目錄的相對路徑)到容器中的

當使用本地目錄為源目錄時,推薦使用 COPY 。一般格式為 COPY 。例如我們要拷貝當前目錄到容器中的 /app 目錄下,我們可以這樣操作:

COPY . /app

WORKDIR

WORKDIR 用於配合 RUN,CMD,ENTRYPOINT 命令設置當前工作路徑。可以設置多次,如果是相對路徑,則相對前一個 WORKDIR 命令。預設路徑為/。一般格式為 WORKDIR /path/to/work/dir 。例如我們設置/app 路徑,我們可以進行如下操作:

WORKDIR /app

RUN

RUN 用於容器內部執行命令。每個 RUN 命令相當於在原有的鏡像基礎上添加了一個改動層,原有的鏡像不會有變化。一般格式為 RUN 。例如我們要安裝 python 依賴包,我們做法如下:

RUN pip install -r requirements.txt

EXPOSE

EXPOSE 命令用來指定對外開放的埠。一般格式為 EXPOSE [...]

例如上面那個例子,開放5000埠:

EXPOSE 5000

ENTRYPOINT

ENTRYPOINT 可以讓你的容器表現得像一個可執行程式一樣。一個 Dockerfile 中只能有一個 ENTRYPOINT,如果有多個,則最後一個生效。

ENTRYPOINT 命令也有兩種格式:

ENTRYPOINT ["executable", "param1", "param2"] :推薦使用的 exec形式

ENTRYPOINT command param1 param2 :shell 形式

例如下麵這個,我們要將 python 鏡像變成可執行的程式,我們可以這樣去做:

ENTRYPOINT ["python"]

CMD

CMD 命令用於啟動容器時預設執行的命令,CMD 命令可以包含可執行文件,也可以不包含可執行文件。不包含可執行文件的情況下就要用 ENTRYPOINT 指定一個,然後 CMD 命令的參數就會作為ENTRYPOINT的參數。

CMD 命令有三種格式:

CMD ["executable","param1","param2"]:推薦使用的 exec 形式。

CMD ["param1","param2"]:無可執行程式形式

CMD command param1 param2:shell 形式。

一個 Dockerfile 中只能有一個CMD,如果有多個,則最後一個生效。而 CMD 的 shell 形式預設調用 /bin/sh -c 執行命令。

CMD 命令會被 Docker 命令行傳入的參數覆蓋:docker run busybox /bin/echo Hello Docker 會把 CMD 里的命令覆蓋。

例如我們要啟動 /app ,我們可以用如下命令實現:

CMD ["app.py"]

當然還有一些其他的命令,我們在用到的時候再去一一講解一下。

構建Dockerfile

我們大體已經把Dockerfile的寫法講述完畢,我們可以自己動手寫一個例子:

mkdir static_web
cd static_web
touch Dockerfile
然後 vi Dockerfile  開始編輯該文件
輸入 i 開始編輯

以下是我們構建的Dockerfile內容

FROM nginx
MAINTAINER Angel_Kitty <[email protected]>
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

編輯完後 按 esc 退出編輯
然後  :wq    寫入 退出

我們在 Dockerfile 文件所在目錄執行:

docker build -t angelkitty/nginx_web:v1 .

這個命令就是創建一個docker鏡像()

我們解釋一下, -t 是為新鏡像設置倉庫和名稱,其中 angelkitty 為倉庫名, nginx_web 為鏡像名, :v1 為標簽(不添加為預設 latest )

我們構建完成之後,使用 docker images 命令查看所有鏡像,如果存在 REPOSITORY 為 nginx 和 TAG 是 v1 的信息,就表示構建成功

接下來使用 docker run 命令來啟動容器

docker run --name nginx_web -d -p 8080:80 angelkitty/nginx_web:v1

如圖,證明我們創建的docker服務正在運行。

這條命令會用 nginx 鏡像啟動一個容器,命名為 nginx_web ,並且映射了 8080 埠,這樣我們可以用瀏覽器去訪問這個 nginx 伺服器:http://localhost:8080/ 或者 http://本機的IP地址:8080/,由於這裡我是在伺服器啟動的,nginx沒有做反代,這裡就不演示了訪問後的效果了。

這樣一個簡單使用 Dockerfile 構建鏡像,運行容器的示例就完成了!

asp.net core 實戰docker

下文會詳細介紹asp.net core 配置docker鏡像,然後伺服器實戰docker部署並作nginx反代。

在這裡我們拋出幾個問題:

  1. asp.net core 做成鏡像並部署是一個什麼樣的流程

  2. 開發環境和伺服器不一致會不會有影響,eg:我們用window開發,項目實際是部署在Linux上

鏡像選取

  1. 用於開發和生成 .NET Core 應用的映像(microsoft/dotnet:2.1-sdk),.NET Core,包含 SDK,適用於 Linux 和 Windows(多體繫結構)

  2. 用於運行 .NET Core 應用的映像(microsoft/dotnet:2.1-aspnetcore-runtime),ASP.NET Core,包含僅運行時和 ASP.NET Core 優化,適用於 Linux 和 Windows(多體繫結構)

為什麼是多個映像? 因為在開發、生成和運行容器化應用程式時,通常具有不同的優先順序。 通過為這些單獨的任務提供不同的映像,Microsoft 有助於優化開發、生成和部署應用程式的單獨進程

在開發期間,重要的是可迴圈訪問更改的速度以及調試更改的能力。 與更改代碼的能力和快速查看更改相比,映像的大小不是那麼重要。

在生產中重要的是基於生產 .NET Core 映像部署和啟動容器的速度。 因此,基於 microsoft/dotnet:2.1-aspnetcore-runtime 的僅運行時鏡像很小,以便它可以通過網路從 Docker 註冊表快速傳輸到 Docker 主機,在生產鏡像中,只放置運行應用程式所需的二進位文件和其他內容

aspdotnet

接下來通過實戰項目,詳細的給大家介紹一下asp.net core在docker中的部署

  1. 創建asp.net core mvc 項目

dotnet new mvc -o website

cd website

ls
...

dotnet dev-certs https --trust

dotnet watch run

創建mvc項目到website 文件夾下,cd 進入文件夾 dotnet watch run 先本地運行一下項目,如果沒有問題下麵創建Dockerfile文件

  1. 創建dockerfile文件

這裡我們用的是.net core 2.2 sdk


FROM microsoft/dotnet:2.2-sdk AS build
WORKDIR /app

# copy csproj and restore as distinct layers

# COPY *.sln .
COPY *.csproj ./
RUN dotnet restore

# copy everything else and build app

COPY . ./
WORKDIR /app
RUN dotnet publish -c Release -o out


FROM microsoft/dotnet:2.2-aspnetcore-runtime AS runtime
WORKDIR /app
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet", "website.dll"]
  1. 創建環境區分文件 Directory.Build.props

這裡我們可以避免開發環境的bin和obj與容器中bin和obj的衝突


<Project>

  <PropertyGroup>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**/*</DefaultItemExcludes>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/bin/**/*</DefaultItemExcludes>
  </PropertyGroup>

  <PropertyGroup Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' == 'true'">
    <BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/container/</BaseIntermediateOutputPath>
    <BaseOutputPath>$(MSBuildProjectDirectory)/bin/container/</BaseOutputPath>
  </PropertyGroup>

  <PropertyGroup Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' != 'true'">
    <BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/local/</BaseIntermediateOutputPath>
    <BaseOutputPath>$(MSBuildProjectDirectory)/bin/local/</BaseOutputPath>
  </PropertyGroup>
  
</Project>
  1. 創建asp.net core docker 鏡像

docker build --pull -t dongshengpro/websiteimage:1.0 .

  • win下不要加倉庫,直接構建鏡像,如下:

docker build --pull -t websiteimage:1.0 .

  1. 開發環境,運行鏡像

docker run --name websiteimage:1.0 --rm -it -p 8090:80 websiteimage:1.0

  1. 生產環境 運行鏡像

docker run --name websiteimage:1.0 -d -p 8090:80 websiteimage:1.0

-d 會直接將容器做成服務

linux 上同理

docker中用到的命令補充說明

在win上的時候,有時候,我們運行docker 容器,可能需要通過查看一下docker 容器ip

docker exec 鏡像明 ipconfig

Windows using Linux containers

docker run --rm -it -p 8000:80 -v c:\git\dotnet-docker\samples\aspnetapp:/app/ -w /app/aspnetapp microsoft/dotnet:2.2-sdk dotnet watch run

You can use CTRL-C to terminate dotnet watch. Navigate to the site at http://localhost:8000 in your browser.

macOS or Linux using Linux containers

docker run --rm -it -p 8000:80 -v ~/git/dotnet-docker/samples/aspnetapp:/app/ -w /app/aspnetapp microsoft/dotnet:2.2-sdk dotnet watch run

You can use CTRL-C to terminate dotnet watch. Navigate to the site at http://localhost:8000 in your browser.

Windows using Windows containers

docker run --rm -it -p 8000:80 -v c:\git\dotnet-docker\samples\aspnetapp:c:\app\ -w \app\aspnetapp --name aspnetappsample microsoft/dotnet:2.2-sdk dotnet watch run

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現在互聯網巨頭,都已經轉投到人工智慧領域,而人工智慧的首選編程語言就是python,未來前景顯而易見。那麼問題來了,想學Python,Python工程師工資一般多少?值得去學嗎? 最近開始整理python的資料,會陸續放到博客中存檔。找了幾個qq群,其中有一個群78486745。後面就沒怎麼加群了, ...
  • """小白隨筆,大佬勿噴"""#鍵盤輸入from pynput.keyboard import Key,Controller,Listenerkeyboard = Controller()keyboard.press("a") #按下akeyboard.release("a") #鬆開akeyboa ...
  • 服務端獲取客戶端請求IP地址,常見的包括:x forwarded for、client ip等請求頭,以及remote_addr參數。 一、remote_addr、x forwarded for、client ip remote\_addr:指的是當前直接請求的客戶端IP地址,它存在於tcp請求體中 ...
  • 【題目背景】 在成功地發明瞭魔方之後,魯比克先生髮明瞭它的二維版本,稱作魔板。這是一張有8個大小相同的格子的魔板: 【題目描述】 我們知道魔板的每一個方格都有一種顏色。這8種顏色用前8個正整數來表示。可以用顏色的序列來表示一種魔板狀態,規定從魔板的左上角開始,沿順時針方向依次取出整數,構成一個顏色序 ...
  • 以前寫過介紹HashMap的文章,文中提到過HashMap在put的時候,插入的元素超過了容量(由負載因數決定)的範圍就會觸發擴容操作,就是rehash,這個會重新將原數組的內容重新hash到新的擴容數組中,在多線程的環境下,存在同時其他的元素也在進行put操作,如果hash值相同,可能出現同時在同 ...
  • 此代碼是上一期的改版 需要用到的Python庫有 1.pygame 2.time 3.xmusic(我自己寫的用來做音樂索引) 4.colorama(美觀) 推薦使用pip安裝 方法: pip install 庫 導入步驟: 1.下載xmusic(點擊藍色字體下載) 2.把下載好的文件放到Pytho ...
  • Spring Boot 編寫自己的"過濾器" 又好久沒有寫博客進行總結了,說實話,就是 "懶",懶得總結,懶得動.之所以寫這篇博客,是因為最近對接公司SSO服務的時候,需要自定義攔截器,spring mvc 中xml的配置文章可以在網上找到很多,但是由於我用的是 Spring boot ,你也知道, ...
  • 答案:是線程安全的,只讀不寫多線程下,完全不需要加鎖! 測試代碼: 模擬5萬個線程讀字典,看看是否混亂: 完全不需要擔心,放心 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...