2024年7月19日 星期五

Docker 介紹 (如何使用 Docker-compose 建置 PHP+MySQl+Nginx 環境)

什麼是 Docker ?

Docker 是一種軟體平台,它可以快速建立、測試和部署應用程式。為什麼可以快速建立呢?因為 Docker 會將軟體封裝到名為『容器』的標準單位。其中會包含程式庫、系統工具、程式碼、執行軟體所需的所有項目。 剛剛有提到容器 (Container),是一種虛擬化技術,它高效率虛擬化及易於遷移和擴展的特性,非常適合現代雲端的開發及佈署。那 Container 與傳統的虛擬機有什麼差別呢?我們來看看下面這張圖


Container 與 VM 的差異

Container 與 VM 的差異

可以看到 Container 是以應用程式為單位,而 VM 則是以作業系統為單位。Container 是一個封裝了相依性資源與應用程式的執行環境 ; VM 則是一個配置好 CPU、RAM 與 Storage 的作業系統,為了更好的做區別,我把 Container、VM 兩個差別用表格來說明~

區別比較ContainerVM
單位應用程式作業系統
適用服務多使用於微服務使用較大型的服務
硬體資源是以程式為單位,需要的硬體資源很少VM 會先佔用 CPU、RAM 等等硬體資源,不管有沒有使用都會先佔用
造成衝突Container 間是彼此隔離的,因此在同一台機器可以執行不同版本的服務會因為版本不同造成環境衝突
系統支援數量單機支援上千個容器一般最多幾十個
優點1 . Image 較小,通常都幾 MB
2 . 啟動速度快,通常幾秒就可以生成一個 Container
3 . 更新較為容易,只需要利用新的 Image 重新啟動就會更新了
1 . 因為硬體層以上都虛擬化,因此安全性相對較高
2 . 系統選擇較多,在 VM 可以選擇不同的 OS
3 . 不需要降低應用程式內服務的耦合性,不需要將程式內的服務個別拆開來部署
缺點1 . 安全性較 VM 差,因為環境與硬體都與本機共用
2 . 在同一台機器中,每一個 Container 的 OS 都是相同的,無法一個為 Windows、一個為 Linux,還是依賴 Host OS
3 . Container 通常會切成微服務的方式作部署,在各元件中的網路連結會比較複雜
1 . Image 的大小通常 GB 以上,比 Container 大很多
2 . 啟動速度通常要花幾分鐘,因此服務重啟速度較慢
3 . 資源使用較多,因為不只程式本身,還要將一部分資源分給 VM 的作業系統

總結

  • 更快速的交付和部署:對於開發和維運人員來說,最希望就是一次建立或設定,可以再任意地方正常運行。開發者可以使用一個標準的映像檔來建立一套開發容器,開發完成之後,維運人員可以直接使用這個容器來部署程式。Docker 容器很輕很快!容器的啟動時間都是幾秒中的事情,大量地節約開發、測試、部署的時間。

  • 更有效率的虛擬化:Docker 容器的執行不需要額外的虛擬化支援,它是核心層級的虛擬化,因此可以實作更高的效能和效率。

  • 更輕鬆的遷移和擴展:Docker 容器幾乎可以在任意的平台上執行,包括實體機器、虛擬機、公有雲、私有雲、個人電腦、伺服器等。 這種兼容性可以讓使用者把一個服務從一個平台直接遷移到另外一個。

  • 更簡單的管理:使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分發和更新,從而實作自動化並且有效率的管理。


Docker 基本概念

  • Dockerfile
  • 映像檔 (Image)
  • 容器 (Container)
  • 倉庫 (Repository)

這四個是 Docker 最基本的組成,了解後就可以知道整個 Docker 的生命週期。

Dockerfile

開發人員在使用 Docker 時發現,大多現成的 Docker 映像檔無法滿足他們的需求,因此需要一種能夠生成映像檔的工具。Dockerfile 是一種簡易的文件檔,裡面包含了建立新映像檔所需的指令。

Dockerfile 語法主要由 Command(命令)和 Argument (參數選擇)兩大元素組成。以下是一個簡易的 Dockerfile 示意圖:

命令式語法+選擇參數(Command + Argument)


映像檔 (Image)

Docker 映像檔是一個唯獨的模板。

例如:一個映像檔可在包含一個完整的 Linux 作業系統環境,裡面可以只安裝 Nginx 或使用者會使用到的其他應用程式。

我們會使用映像檔來建立 Docker 的容器 (Container) ,Docker 也提供很簡單的機制來建立映像檔或是更新現有的映像檔,也可以去下載別人已經做好的映像檔。


容器 (Container)

Docker 是利用容器來執行應用程式。

每一個容器都是由映像檔所建立的的執行程式。它可以被啟動、開始、停止、刪除。且每一個容器都是相互隔離的,不會相互影響。


Docker 實作

本章節會介紹 Docker 三大組件映像檔 (image)、容器 (Container)、倉庫 (Repository) 要如何實際操作,以及他們的關聯性是什麼~

映像檔 (Image)

本小節會介紹有關映像檔的內容,包括:

  • 如何從倉庫取得映像檔
  • 如何管理本地主機上的映像檔
  • 映像檔實作 (Dockerfile)

如何從倉庫取得映像檔

我們可以先到 Docker hub 上面看看有什麼服務或程式想要下載來做使用 [ 詳細介紹會放到倉庫 (Repository) 章節],找到想要的服務,我們可以下 docker pull {要下載的服務、程式名稱} ,我們這邊就先下載 Mysql 這個映像檔。

  • mysql
$ docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
15115158dd02: Pull complete
.... 省略 ....
Digest: sha256:b17a66b49277a68066559416cf44a185cfee538d0e16b5624781019bc716c122
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest

由於我們下載的沒有加任何的 tag ,也就是版本,所以我們都是下載最新版 latest ,如果想要下載特定版本,可以在服務名稱後面加上 :{版本} ,就可以下載對應的版本囉!


如果有標記 Official Image 就代表是官方釋出的映像檔 ~ 在穩定性以及安全上更有保障,所以大家可以優先下載歐!


Docker hub 下載 Image

Docker hub 下載 Image


管理本地主機上的映像檔

查看映像檔 (images)

當我們下載好映像檔後,可以使用 docker images 來列出本機已下載的映像檔。

$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
php          latest    d6229b88aa29   3 days ago    484MB
mysql        latest    826efd84393b   6 days ago    521MB
nginx        latest    c919045c4c2b   13 days ago   142MB

我們來看看都列出哪些訊息吧!

  • REPOSITORY:來自於哪一個倉庫,像是 php、mysql、nginx。
  • TAG:映像檔的標籤,因為我們都下載最新版本所以是 latest。
  • IMAGE ID:它的唯一 ID 號碼。
  • CREATED:建立時間。
  • VIRTUAL SIZE:映像檔大小。

儲存映像檔 (save)

想要儲存映像檔,可以使用 docker save {映像檔名稱} > {檔案名稱}.tar,來做儲存。

$ docker save mysql > mysql.tar
$ ls | grep 'mysql'
mysql.tar

刪除映像檔 (rmi)

想要刪除映像檔,可以使用 docker rmi {映像檔名稱} 來做刪除。

$ docker rmi demo-image
Untagged:demo-image:latest
Deleted: sha256:1f56acbcbe9ec613a37e26934a84d98bed73879059f424dc69754520086baa37

想要同時刪除映像檔時,可以先用 docker images -aq 列出全部映像檔的 IMAGE ID,再一起刪除。

docker rmi -f $(docker images -aq)
  • 注意!刪除映像檔(Image)時,要先用 docker rm {容器} 去刪除所有依賴這個映像檔的容器。

接著要怎麼建立自己的映像檔呢?我們要使用 Dockerfile 來建立映像檔。

映像檔實作

撰寫 Dockerfile 映像檔

Dockerfile 是一種文字格式的設定檔,可以透過 Dockerfile 快速建立自訂的映像檔,換句話說,Dockerfile 就像是建置 Docker Image 的腳本。

舉個例子:可以把自己想像成一位設計師,設計好房子的格局、擺飾等,畫好設計圖 (Dockerfile) 後,最後請師傅 (Docker) 依你的構思完成就可以了。


我們就來開始實作一個 Dockerfile 吧 ~

  1. 我們先創建一個來放 Dockerfile 的資料夾,可以直接在路徑下建立出映像檔
mkdir demo-dockerfile
cd demo-dockerfile/

Dockerfile 結構,大致可以分為四個部分

  • 基礎映像檔資訊
  • 維護者資訊
  • 映像檔操作指令
  • 容器啟動時需執行的指令

  1. 我們有說過 Dockerfile 是一個文字格式的設定檔,所以我們用 vim 來編寫 Dockerfile。
vim Dockerfile

# 基礎映像檔資訊
FROM nginx:latest

# 維護者資訊
LABEL maintainer="880831ian@gmail.com"

# 映像檔操作指令
RUN apt-get update -y\
    && apt-get install nginx -y

# 運行時容器提供服務的通道
EXPOSE 80

# 容器啟動時需執行的指令
CMD ["nginx","-g","daemon off;"]

FROM nginx:latest

第一行為必要的指定基礎映像檔,這邊使用 nginx 作為基礎映像檔,我們用最新版本,所以是 latest。


LABEL maintainer="880831ian@gmail.com"

維護者資訊想不也是不可以少的,這邊也可以輸入 Email 資訊,只是要注意的是此資訊會寫入產出映像檔的 Author 名稱屬性中。


RUN apt-get update -y\ && apt-get install nginx -y

這邊是最重要的部分,想要在映像檔案上設定或安裝都需要將命令寫在這,格式必須依 RUN ,RUN 指令後面放 Linux 指令,如果指令太長可以使用\來換行。 -y 是在安裝 Nginx,會同意所有進行中所出現的問題。


EXPOSE 80

設定運行時容器提供服務的通道。


CMD ["nginx","-g","daemon off;"]

最後就是啟動指定容器時預設執行的指令,格式是 CMD [“executable”,“param1”,“param2”]。


Docker 運行 Nginx 時為什麼要使用 daemon off;

因為 Docker 容器啟動時,默認會把容器內部第一個進程,作爲 docker 容器是否正常運行的依據,如果 docker 容器 pid = 1 到進程就掛了,docker 就會退出!

Docker 未執行自定義的 CMD 之前, Nginx 的 pid 是 1,執行到 CMD 之後,Nginx 就在後台運行,bash 或是 sh 的腳本就會變成 pid =1 。

所以一但執行完 CMD,Nginx 容器就會退出了,所以才需要加上 -g daemon off;

在 Nginx 官方的 Docker Repository 也有說明,在 Complex configuration 內。


順便說一下使用 Dockerfile 的優點:1 . 可以進行 Git 版控,讓你管理或分享更方便 2 . 佔用容量小,因為只是純文字檔而已。


使用 Dockerfile 建立映像檔

我們已經撰寫完 Dockerfile 檔案了,接下來要執行來產生映像檔,我們要使用 docker build 來建立,我們一起來看看吧

docker build -t demo-image .

因為我們在 dockerfile 的目錄下,所以直接使用 “.” 來做建立動作,也可以使用 -f 來指定 dockerfile 的路徑位置。使用 -t 來設定映像檔的名稱,我們這邊取名叫 demo-image。

[+] Building 2.7s (7/7) FINISHED
 => [internal] load build definition from Dockerfile                                                                   0.0s
 => => transferring dockerfile: 44B                                                                                    0.0s
 => [internal] load .dockerignore                                                                                      0.0s
 => => transferring context: 2B                                                                                        0.0s
 => [internal] load metadata for docker.io/library/nginx:latest                                                       2.6s
 => [auth] library/ubuntu:pull token for registry-1.docker.io                                                          0.0s
 => [1/2] FROM docker.io/library/nginx:latest@sha256:8ae9bafbb64f63a50caab98fd3a5e37b3eb837a3e0780b78e5218e63193961f  0.0s
 => CACHED [2/2] RUN apt-get update -y    && apt-get install nginx -y                                                  0.0s
 => exporting to image                                                                                                 0.0s
 => => exporting layers                                                                                                0.0s
 => => writing image sha256:1f56acbcbe9ec613a37e26934a84d98bed73879059f424dc69754520086baa37                           0.0s
 => => naming to docker.io/demo-image

完成後我們使用 docker images 來看看是否建立成功。

$ docker images
REPOSITORY         TAG       IMAGE ID       CREATED       SIZE
demo-image   	   latest    1f56acbcbe9e   2 hours ago   166MB
php                latest    d6229b88aa29   4 days ago    484MB
mysql              latest    826efd84393b   6 days ago    521MB
nginx              latest    c919045c4c2b   13 days ago   142MB

執行容器的部分,我們放到容器 (Container)的章節在介紹 ~


容器 (Container)

我們在介紹指令前,先來了解一下 Dockerfile、Docker Image、Docker Container 這三個的關係,可以先參考以下圖片

容器 Container 組成

容器 Container 組成


我們在啟動 Container 時,會有這三個部分組成,最底層是映像檔 (Image),這一層主要是透過撰寫 Dockerfile 之後 build 出來的 Docker Image,就像我們前面說的它是一個唯獨的檔案。執行啟動了 Docker Container,就會加上第二層,就是需要先 Init Container 的設定,例如是 hostname、環境變數、網路連接等系統設定,最後最上層再加上一層讓使用者可以在此層去讀寫資料。


有關於容器 (Container) 的指令非常多,光是簡單的 run 就有很多參數,我們先列出比較常用且基本的 Container 指令~

Container 執行時的操作

執行容器 (run)

我們想要創建一個新的容器並運行,就可以使用 docker run,我們來看看他可以使用哪些參數吧!

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  • OPTIONS 說明:
參數描述
-d後台運行容器
-i命令互動模式,通常與 -t 同時使用
-t為容器重新分配一個假裝的輸入終端,通常與 -i 同時使用
-p指定容器與本機的 Port ,格式是 主機 Port : 容器 Port
–name="{名稱}"為容器設定名稱
–net="{網路類型}"指定容器的網路連接類型,支援 bridge/host/none/container 四種模式
–link="{其他容器}"添加連接到另一個容器
–volume,-v將容器檔案路徑映射到本地端,格式是 本機路徑:容器路徑

我們啟動我們下載好的 Nginx 來試試看吧!

$ docker run -d -p 7777:80 --name="demo-nginx" -v /Users/ian_zhuang/Desktop/data:/usr/share/nginx/html nginx
31a4a4a56e3ef2fb75d538c4c9eea4914ac506a84a6ff97e1fbbb6c3213cc6b7

我們將 Nginx 容器在背景執行,且將預設的 80 Port 與本機的 7777 Port 綁在一起,讓我們在本機瀏覽 7777 Port 會直接導向容器的 80Port,設定容器的名字叫做 “demo-nginx" ,我們 Nginx 容器的檔案路徑映射到本地端的桌面 data 資料夾,我們就可以在本機新增檔案同步到容器中。

Nginx 預設目錄 /usr/share/nginx/html

 


顯示容器 (ps)

使用 docker ps 來檢查一下是否啟動成功 (ps 可以顯示映像檔的基本資訊,如果沒有加 -a 只會顯示執行中的容器)

$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED              STATUS              PORTS                  NAMES
31a4a4a56e3e   demo-image   "nginx -g 'daemon of…"   About a minute ago   Up About a minute   0.0.0.0:7777->80/tcp   demo-nginx

接著我們測試是否有把桌面 data 資料夾掛到容器的路徑,我們先在 data 新增一個 hello.html ,裡面隨意輸入,瀏覽一下 http://127.0.0.1:7777/hello.html ,看看是否成功。


容器 Container -volume 測試

容器 Container -volume 測試


顯示容器紀錄 (logs)

想要看到我們執行 Container 的紀錄,可以使用 logs 指令來顯示。

$ docker logs demo-nginx
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
... 省略 ...
2022/03/15 09:27:51 [notice] 1#1: start worker process 33
2022/03/15 09:27:51 [notice] 1#1: start worker process 34
2022/03/15 09:27:51 [notice] 1#1: start worker process 35

刪除容器 (rm -f)

想要刪除不需要的 Container,可以使用 rm 指令來做刪除,-f 是強制刪除容器。

$ docker rm -f demo-nginx
demo-nginx

進入容器 (exec)

想要進入 container 來查看資料或是修改檔案,可以使用 exec 來進入容器中。

$ docker exec -it demo-nginx /bin/bash
root@31a4a4a56e3e:/# ls
bin  boot  dev	docker-entrypoint.d  docker-entrypoint.sh  etc	home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@31a4a4a56e3e:/# cd usr/bin/
root@31a4a4a56e3e:/usr/bin# pwd
/usr/bin

匯出檔案 (export)

我們前面有提到說,如果刪除了容器,以前寫入的資料也會不見,如果想要輸出資料,可以使用 export 將可讀可寫的那一層匯成檔案。

$ docker export demo-nginx > demo-nginx.tar
$ ls | grep 'demo'
demo-nginx.tar

save 跟 export 的區別:

還記得我們在儲存映像檔的時候有介紹到 save 嗎,那他跟 export 的區別是什麼呢?我們可以理解成

save 是把 Docker Image 原始檔做儲存,export 是把修改 Docker Image 的內容都一併儲存。


匯入檔案 (import)

有匯出檔案,當然也有匯入檔案拉,可以使用 import 將我們匯出的檔案匯入 Docker Image 裡面。

$ cat ~/Desktop/demo-nginx.tar| docker import - import-nginx
sha256:7106935f0bfbdbb84f9eb20edb8cdb2c53207f5e0963f6a4e89d8267e9d98c56

$ docker images
REPOSITORY     TAG       IMAGE ID       CREATED          SIZE
import-nginx   latest    7106935f0bfb   19 seconds ago   140MB

Container 的狀態

檢查容器狀態 (inspect)

想要查看容器的狀態數據,可以使用 inspect 來顯示。

[
    {
        "Id": "sha256:1f56acbcbe9ec613a37e26934a84d98bed73879059f424dc69754520086baa37",
        "RepoTags": [
            "demo-image:latest"
        ],
        "RepoDigests": [],
        "Parent": "",
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2022-03-15T03:02:26.8321887Z",
        "Container": "",
        "ContainerConfig": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
.... 省略 ....

查看容器的 CPU、記憶體及網路使用 (stats)

想要查看容器的 CPU、記憶體及網路使用,可以使用 stats 來顯示。

CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
31a4a4a56e3e   demo-nginx   0.00%     5.797MiB / 1.939GiB   0.29%     6.29kB / 2.83kB   1.46MB / 20.5kB   5

倉庫 (Repository)

我們在映像檔的章節有使用 docker pull 來下載別人的映像檔來使用,那我們要如何把我們做好的上傳上去 Docker hub 呢!(由於 Docker hub 是公開平台,所以大家都可以自由的下載映像檔,所以是公司機密的映像檔,就要避免上傳歐!)

$ docker login
Authenticating with existing credentials...
Login Succeeded

由於我有下載桌面版的 Docker ,所以登入時不需要再另外設定!


我們在上傳到 Docker hub 之前,需要先修改 Image 的 tag ,格式 docker tag {Image Name} {DockerHub帳號}/{想要取的 Image Name}

$ docker images | grep 'demo-image'
demo-image   latest    1f56acbcbe9e   24 hours ago   166MB

$ docker tag demo-image 880831ian/demo-image

$ docker images | grep 'demo-image'
880831ian/demo-image   latest    1f56acbcbe9e   24 hours ago   166MB
demo-image             latest    1f56acbcbe9e   24 hours ago   166MB

接下來就使用 docker push,將映像檔上傳到 Docker hub 上!

$ docker push 880831ian/demo-image
Using default tag: latest
The push refers to repository [docker.io/880831ian/demo-image]
7722c88c8d69: Pushed
68a85fa9d77e: Mounted from library/ubuntu
latest: digest: sha256:814caacaf3dad3eccb43dc9bcad635d0473bd5946295d40ca1ec23d13a5f6d0f size: 741

我們也登入 Docker hub 看一下,是不是真的上傳成功了~


repository

repository


Docker 進階

本章節會分成三個常用功能來說明

  • Volumes 介紹
  • Network 模式介紹和比較
  • Docker-compose 介紹與實作

Volumes 介紹

我們在先前介紹 Container 時,也有說到,Container 會分成 Image 層、Init 層以及使用者可讀可寫層的這三層。當我們將 Container 刪除後,存放在 Docker Container 上的資料也會不見,雖然可以用 export 來儲存,但我們應該在根本上解決問題。

所以我們可以使用兩種方式來解決!

  1. 在執行 docker run 指令時加入 -v 參數,將 Container 的檔案路徑映射到本地端的檔案路徑。
  2. 在撰寫 Dockerfile 時,加入 VOLUME 指令,可以將資料存放在實體主機上。使用這個方法還要搭配我們介紹 Container 的狀態 > 檢查容器狀態 (inspect) ,來查詢本地端檔案的存放路徑在哪。

使用 -v 指令將容器映射到本地端

在使用 docker run 指令時,使用 -v 將容器檔案路徑映射到本地的檔案路徑。

$ docker run -it -v /Users/ian_zhuang/Desktop/data:/storage centos /bin/bash
latest: Pulling from library/centos
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@a99b41fba3ca /]#

我們在著面的 data 資料夾隨意新增檔案或是資料,再進入 Docker Container 內的 /storage (該檔案是因為使用 -v 而新增的資料夾) ,看看有沒有同步新增。

[root@a99b41fba3ca /]# cd storage
[root@a99b41fba3ca storage]# pwd
/storage
[root@a99b41fba3ca storage]# ls
1.html	2.html	3.html

Dockerfile VOLUME 使用

我們先打開上次的 Dockerfile 檔案,在基礎映像檔資訊的底下使用 VOLUME 指令,加入 storage 資料夾,再將 Image Build 起來,啟動 Container,在 /storage 裡面隨便新增資料,最後我們在用 docker inspect 指令來找映射在本地端的路徑。


  1. 在基礎映像檔資訊的底下使用 VOLUME 指令,加入 storage 資料夾
# 基礎映像檔資訊

FROM ubuntu:latest
VOLUME ["/storage"]
.... 省略 ....

  1. 建立映像檔
$ docker build -t demo-image:v2 .

[+] Building 1.3s (6/6) FINISHED
 => [internal] load build definition from Dockerfile                                                                                            0.0s
 => => transferring dockerfile: 44B                                                                                                             0.0s
 => [internal] load .dockerignore                                                                                                               0.0s
 => => transferring context: 2B                                                                                                                 0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                                                                1.2s
 => [1/2] FROM docker.io/library/ubuntu:latest@sha256:8ae9bafbb64f63a50caab98fd3a5e37b3eb837a3e0780b78e5218e63193961f9                          0.0s
 => CACHED [2/2] RUN apt-get update -y    && apt-get install nginx -y                                                                           0.0s
 => exporting to image                                                                                                                          0.0s
 => => exporting layers                                                                                                                         0.0s
 => => writing image sha256:0618bb2685ecfe200d9df4a91380d482031352d0e00cbfdf70fcd063aa8654fa                                                    0.0s
 => => naming to docker.io/library/demo-image:v2

  1. 啟動 Container,並在 /storage 內新增隨意資料
$ docker run -it demo-image:v2 /bin/bash

root@4f8712562dfe:/# echo "Hello ian" > /storage/helloworld.txt
root@4f8712562dfe:/# ll /storage
total 12
drwxr-xr-x 2 root root 4096 Mar 16 05:39 ./
drwxr-xr-x 1 root root 4096 Mar 16 05:38 ../
-rw-r--r-- 1 root root   10 Mar 16 05:39 helloworld.txt

  1. 使用 inspect 指令,來找到 Volume 在本地端映射的資料夾路徑,看看裡面有沒有我們在 Container 裡面新增的資料吧
$ docker inspect -f '{{.Mounts}}' 4f8712562dfe
[{volume 4fe10ca3f...省略 /var/lib/docker/volumes/4fe10ca3f234633164d9b3c541893c68db1b4f98806525076a2edd5c1c7863c4/_data /storage local  true }]

$ docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
/ # cd /var/lib/docker/volumes/4fe10ca3f234633164d9b3c541893c68db1b4f98806525076a2edd5c1c7863c4/_data
/var/lib/docker/volumes/4fe10ca3f234633164d9b3c541893c68db1b4f98806525076a2edd5c1c7863c4/_data # ls
helloworld.txt

mac OS 找不到 /var/lib/docker/volumes: 由於 macOS 下的 docker 實際是在 vm 裡又多加一層,所以沒辦法直接訪問 /var/lib/docker/volumes,必須先透過以下指令進入 VM 中。

docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh

詳細內容可以參考 Where is /var/lib/docker on Mac/OS X


容器與容器之間資料共享

如何啟用容器與容器之間的資料共享,可以用以下方式

  1. 先啟動第一個容器指令如下
docker run -it -v /data --name=container1 centos /bin/bash
[root@ a0307ce757ca /]#

  1. 另二個容器指令如下
docker run -it --volumes-from container1 --name=container2 centos /bin/bash
[root@720d57983cd4 /]#
  • --volumes-from 參數指定 container1 的資料會與 container2 做共享。

  1. 我們在第一個容器,進入 /data 資料夾,隨機輸入資料
[root@a0307ce757ca /]# cd /data/
[root@a0307ce757ca data]# echo "ian~" > hello.txt

  1. 再來看一下第二個容器 /data 資料夾,是否有我們在容器(a0307ce757ca)產生的資料
[root@720d57983cd4 /]# cat /data/hello.txt
ian~

Network 模式和比較

在執行 docker run 其中一個參數是 --net ,他可以設定 Container 要使用哪一種的網路模式,以下分別說明這些網路模式

  • none:在執行 Container 時,網路功能是關閉的,所以無法與此 Container 連線。
  • container:使用相同的 Network Namespace ,假設 Container 1 的 IP 是 172.17.0.2,那 Container 2 的 IP 也是 172.17.0.2。
  • host:Container 的網路設定和實體主機使用相同的網路設定,所以 Container 裡面也可以修改實體機器的網路設定,因此使用此模式需要考慮網路安全性上的問題。
  • bridge:Docker 預設就是此網路模式,這個網路模式就像是 NAT 的網路模式,例如實體主機的 IP 是 192.168.1.10 它會對應到 Container 裡面的 172.17.0.2,在啟動 Docker 的服務時會有一個 docker0 的網路卡來做此網路的橋接。
  • overlay:Container 之間可以在不同的實體機器上做連線,例如 H ost 1 有一個 Container 1 ,然後 Host 2 有一個 Container 2,Container 1 可以直接使用 overlay 的網路模式和 Container 2 做網路連線。
  • macvlan:可以直接分配實體網卡的 MAC address 給特定的 Container,讓 Container 透過實體的網卡使用網路。

那我們就來實作每一個網路模式吧!

none

我們使用 docker run指令,在後面加入參數 --net=none ,我們建立 jonlabelle/network-tools (裡面有很多網路測試工具)。

$ docker run -it --net=none jonlabelle/network-tools
[docker@network-tools]$ ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
	    .... 省略 ....

可以看到我們使用 ifconfig 查詢,只有本地端的 127.0.0.1 IP,我們在使用 ping 來測試 google 網站吧

[docker@network-tools]$ ping www.google.com
ping: www.google.com: Try again

container

我們先啟動一個名為 container1 的容器

docker run --name container1 -it jonlabelle/network-tools

再開啟另一個 Terminal 來啟動 container2 的容器,並設定相同的 Network Namespace

docker run --name container2 --net=container:container1 -it jonlabelle/network-tools

一樣使用 ifconfig 查詢,可以發現兩個容器的 IP 都是相同的

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          .... 省略 ....

host

在執行 docker run 指令時,在後面加入參數 --net=host ,來測試 host 模式

docker run --net=host -it jonlabelle/network-tools

可以看到 Container 的網路資訊和實體主機的網路資訊是相同的結果

[docker@network-tools]$ ifconfig
br-36a27cab1817 Link encap:Ethernet  HWaddr 02:42:20:DF:DB:FD
          inet addr:172.20.0.1  Bcast:172.20.255.255  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          .... 省略 ....
host 網路模式

host 網路模式


bridge

在執行 docker run 指令時,在後面加入參數 --net=bridge ,來測試 bridge 模式

docker run --net=bridge -it jonlabelle/network-tools

docker 會新增一個虛擬網卡作為容器網路對外的出口,預設名稱為 docker0,docker0 會跟本機的對外網卡(圖中的 eth0 )相連,藉此取得對外連線的能力,也因為每一個容器都會使用一個 veth device 與 docker0 相連,所以也具備對外連線的能力。

bridge 網路模式

bridge 網路模式


overlay

下圖是說明 Host1 實體主機裡面有 Container1,然後 Host2 實體主機裡面有 Container2,可以透過 Docker overlay 模式將 Container1 和 Container2 連接做溝通。另外還需要一個 Consol 來存連線的資料庫,在使用 overlay 時要先在 Docker 做設定,這樣才能存放 overlay 網路模式的連線資訊。

overlay 網路模式

overlay 網路模式


macvlan

macvlan 的原理就是在本機的網卡上虛擬出很多個子網卡,通過不同的 MAC 位置在數據鏈路層進行網路資料的轉發。

macvlan 網路模式

macvlan 網路模式


Docker-compose

我們在執行多個容器時,需要重複的下 run 指令來執行,以及容器與容器之間要做關聯也要記得每一個之間要怎麼連結,會變得很麻煩且不易管理,所以有了 docker-compose 可以將多個容器組合起來,變成一個強大的功能。

只要寫一個 docker-compose.yml 把所有會使用到的 Docker image 以及每一個容器之間的關聯或是網路的設定都寫上去,最後再使用 docker-compose up 指令,就可以把所有的容器都執行起來囉!


我們就直接來實作我們這次的標題,要使用 docker-compose 來整合 PHP MySQL Nginx 環境。

  1. 我們先開啟一個資料夾,取名叫 docker-compose ,來放置我們的 docker-compose 檔案
  2. 接著新增 docker-compose.yml 檔案,要準備來撰寫我們的設定檔囉! 由於內容有點長,所以我分段說明,(這邊有放已經寫好的檔案歐)

檔案目錄


version: "3.8"

services:
... 省略 ....

可以看到一開頭,會先寫版本,這邊代表的是會使用 3.8 版本的設定檔,詳細版本對照可以參考 Compose file versions and upgrading

services 可以設定用來啟動多的容器,裡面我們總共放了三個容器,分別是 nginx、php、mysql 。

那我們來看看 nginx 裡面放了什麼吧!我會依照程式碼往下說明,有不清楚的可以底下留言!


nginx

nginx:
  build: ./nginx/
  container_name: nginx
  ports:
    - 7777:80
  volumes:
    - ./docker-volume/log/:/var/log/nginx/

nginx 的 build 就是要執行這個 nginx 容器的映像檔,還記得我們也可以使用 Dockerfile 來撰寫映像檔案嗎!?

由於我們還要設定其他內容,所以特別另外拉一個 nginx 資料夾來放置,裡面放了兩個檔案,分別是 Dockerfile、default.conf。

Dockerfile 檔案裡面會使用 nginx 版本 1.20 ,並將 default.conf 複製到容器的 /etc/nginx/conf.d/default.conf 來取代設定。

以及我們使用 ports 將容器 80 Port 指向本機 7777 Port ,格式是 本機 Port : 容器 Port

再使用 volumes 來設定我們 nginx 容器 log 資料夾映射到本機的 ./docker-volume/log/ 資料夾。


php

php:
  build: ./php/
  container_name: php
  expose:
    - 9000
  volumes:
    - ./docker-volume/html/:/var/www/html/

php 的 build 是要執行這個 php 容器的映像檔,由於我們還要設定其他內容,所以特別另外拉一個 php 資料夾來放置 Dokcerfile。

Dockerfile 檔案裡面會使用 php 版本 7.4-fpm,並且在容器執行 docker-php-ext-installmysqli

並將 Port 9000 發佈於本機,再使用 volumes 來設定 /var/www/html 網站根目錄映射到本機的 ./docker-volume/html/ 資料夾。


mysql

mysql:
  image: mysql:8.0.28
  container_name: mysql
  volumes:
    - ./docker-volume/mysql/:/var/lib/mysql
  environment:
    MYSQL_ROOT_PASSWORD: secret
    MYSQL_DATABASE: mydb
    MYSQL_USER: myuser
    MYSQL_PASSWORD: password

mysql 使用的映像檔是 mysql 版本是 8.0.28,我們為了要保留資料庫的資料,所以將容器的 /var/lib/mysql 映射到本地端 ./docker-volume/mysql 資料夾。

最後的環境變數,設定 root 帳號的登入密碼,以及要使用的資料庫、使用者的帳號、使用者的密碼。


最後在上面的 (這邊有放已經寫好的檔案歐) 裡面還有多一個 docker-volume/html 的資料夾,就是我們剛剛映射到本地端的資料夾,資料夾內已經放有連線測試的檔案,輸入網址 http://127.0.0.1:7777/index.php,如果開啟後有顯示下方畫面,就代表我們成功用 docker-compose 將 PHP MySQL Nginx 整合再一起囉!

測試是否成功用 docker-compose 整合 PHP MySQL Nginx

測試是否成功用 docker-compose 整合 PHP MySQL Nginx


參考資料

Docker 官網:https://docs.docker.com/get-started/

什麼是 Docker?:https://aws.amazon.com/tw/docker/

Docker--從入門到實踐:https://philipzheng.gitbook.io/docker_practice/#yuan-chu-chu-ji-can-kao-zi-liao

Dockerfile 建立自訂映像檔 — 架起網站快速又簡單(一):https://medium.com/@jackercleaninglab/dockerfile-%E5%BB%BA%E7%AB%8B%E8%87%AA%E8%A8%82%E6%98%A0%E5%83%8F%E6%AA%94-%E6%9E%B6%E8%B5%B7%E7%B6%B2%E7%AB%99%E5%BF%AB%E9%80%9F%E5%8F%88%E7%B0%A1%E5%96%AE-%E4%B8%80-22b2743f97b9

用 30 天來介紹和使用 Docker:https://ithelp.ithome.com.tw/users/20103456/ironman/1320

Docker 網路簡介:https://godleon.github.io/blog/Docker/docker-network-overview/

Docker-compose Giving static IP in network mode : bridge:https://stackoverflow.com/questions/61949319/docker-compose-giving-static-ip-in-network-mode-bridge

 

 

 資料來源:https://pin-yi.me/blog/docker/docker/

 

Enable Root Login in Ubuntu Ubuntu 22.04

 

By default Ubuntu will not allow root login. You will have to either login to privileged user and then use the sudo command or you can use to sudo su to run as root.

Note: Its never a good idea to run as root.

  • The Ubuntu machine already as user ‘Student” which sudo privileges.

Step 1: Set password for the root.

$ sudo passwd

Set password for the root user.

Step 2: GDM configuration file need to be modified to allow root login. the file is located at /etc/gdm3/custom.conf. Add the line AllowRoot=true in the file.

Add AllowRoot=true to allow root login.

Step 3: Allow the root user to login via GUI.

previous steps allow the root user to login, but it does not allow the root user to login via GUI. the feature is disabled in the configuration file. Comment the line in the file /etc/pam.d/gdm-password that disabled root login via GUI and then we should be able to login as root via Login prompt.

Comment the line which disables the root gui feature.

Step 4: Finally restart the Ubuntu and should be able to login as root via GUI.

Step 5: Click on not listed.

Step 6: Enter the root as username and password which was set in set 1.

Enter root in username and password that was set earlier.

With great power comes great responsibility. Use the root users wisely.

 

資料來源:https://medium.com/@karthiked/enable-root-login-in-ubuntu-ubuntu-22-04-70521607bc7c

2024年7月18日 星期四

Docker 實戰系列(三):使用 Volume 保存容器內的數據

You can find the English version at Sustain Your Data: A Practical Guide to Using Docker Volumes.

這是 Docker 實戰系列文的第三篇,如果還沒看過上一篇的可以先看看 Docker 實戰系列(二):在 DockerHub 上分享自己的 image

之前說過每個 container 都是獨立的,那如果今天我想升級 MySQL 的版本,於是我把正在跑的 mysql:5.5 關掉,然後重新跑一個 mysql:5.7 的 container,那資料庫裡面的資料不就不見了嗎?

沒錯,這時候就需要 volume 了,簡單來說 Volume 就是用來保存容器內的資料的,看看下面這張圖

當你使用 volume 時,docker 會在你的本機上隨機新增一個資料夾作為 Local storage area,大部分會在 /var 底下,然後讓這個資料夾跟 container 裡面的某個資料夾互通。

因為他們是互通的,所以當你 container 裡面的資料夾有任何變更時,本地的資料夾也會跟著變,而且很重要的一點是:container 被刪掉時那個資料夾還會原封不動保留在那邊,因此我們可以利用這個特性保留容器裡面的資料

實際操作

Step 1 — 新增一個 volume

我們新增了一個 volume 叫做 db-data,完成之後可以看到多一個 volume,這時候 docker 已經在本機上新增一個資料夾要給 volume 用

> docker volume create --name db-data
> docker volume ls

Step 2 — 使用 volume

在啟動時加一個 -v 參數,就可以指定 volume 要跟容器內哪一個資料夾連通,這邊用的是 /db/data,實際上使用時可以換成資料庫存放資料的路徑

demo 一下:
1. 剛開始先確認 /db/data 裡面什麼檔案都沒有
2. 接著在容器內新增一個檔案 file
3. 最後再確認檔案在不在

> docker run -v db-data:/db/data -it ubuntu ls -la /db/data
> docker run -v db-data:/db/data -it ubuntu touch /db/data/file
> docker run -v db-data:/db/data -it ubuntu ls -la /db/data

值得留意的是這三個指令是跑在不同的容器裡面,所以也就證明了當容器被關掉時,資料確實還有保存在 volume 內,而且下個容器可以成功讀到上個容器留下的資料

Host Volume

上面那種先 create 再使用的 volume 稱作 named volume,而現在要介紹另外一種叫做 host volume,用來直接指定某個資料夾跟容器內的資料夾連通

來一段 demo:
1. 檢查 ~/app 內沒有 package.json
2. 指定本機的 ~/app 跟容器內的 /app 連通,接著在容器內跑 npm init
3. 跑完再回本機確認有沒有生出 package.json

> ls -la app
> docker run -v ~/app:/app --workdir /app node:slim npm init -y
> ls -la app

上面例子中的 package.json 其實是在容器內生成的,所以有了 volume 之後就可以不用裝 yarn 卻還是可以跑 yarn init

同理,你也可以不用裝 g++ 就能編譯 C++ 原始碼、不用裝 JDK 就可以開發 Java 程式、甚至不用裝 MongoDB 就可以用他來存資料,整台電腦只要裝一個 docker,真是太神了 🎉🎉

總結

這篇講了兩種 volume 希望大家都有看懂,如果想更深入了解可以看看官方文件,在往後的章節為了保存資料將會很常用到他

下一篇要講的是如何將一個應用拆分成多個 container,讓他們分工合作構成你的應用程式,有興趣的人歡迎追蹤我,謝謝大家~

 

 

資料來源:https://larrylu.blog/using-volumn-to-persist-data-in-container-a3640cc92ce4 



使用 docker run -it -v

docker run -it -v /home/kinposw/RichardTestDocker/BindVolumeFolder:/home ubuntu






Docker 實戰系列(二):在 Docker Hub 上分享自己的 image

Larry・Blog

You can find the English version at Pushing Your Docker Images to Docker Hub: A Step-by-Step Guide.

看完上一篇一步一步帶你 dockerize 你的應用之後,我已經會寫 Dockerfile 也知道怎麼 build 出自己的 image 了,但是我要怎麼把 image 分享出去給別人使用呢?沒錯,這就是這篇要講的

Docker Registry

Docker Hub 是官方提供的 Docker Registry,所謂的 Docker Registry 就是一個讓大家可以 pull(下載)或是 push(上傳)image 的地方,把 image 上傳到 Docker Registry 後大家就可以直接 pull 下來用,不用再根據 Dockerfile 自建出 image

官方 VS 非官方 image

在 Docker Hub 上的 image 有分成官方跟非官方兩種,像 ubuntumysql 這種就是官方的,在安全性跟品質上也比較有保證,要使用就直接 docker pull <image> 就可以了

那像 larry850806/nodejs-workspace 這個是我自己 build 出來的 image,前面就會有我的 username,如果要 pull 下來的話就要 docker pull larry850806/nodejs-workspace

Build And Push To Docker Hub

這次要教大家在 Docker Hub 上分享自己的 image,如果還沒有 Docker Hub 帳號的可以先去申請一個,這次也會用 simple-express-server 當做範例,如果你有其他專案可以 build 出 image 也可以拿來試試看

Build From Dockerfile

因為要上傳到 Docker Hub 上面,所以在 build 時要加上自己的 username,像我就是 docker build -t larry850806/simple-express-server .,build 完會多一個叫做 larry850806/simple-express-server 的 image,這個 image 總共是 677 MB(么壽好肥)

Login

在 push 之前必須先跑 docker login 登入,如果有申請帳號的話應該是不會有什麼問題,打打帳號密碼就 ok 了,另外如果你之前已經登入過就不用再次登入囉~ docker 會幫你把 credential 存起來

Push To Docker Hub

登入完就直接跑 docker push larry850806/simple-express-server 把 image push 上去,但你可能會想,這個 image 有 677MB 欸,這樣不就要 push 超久嗎?就像是要傳一個超~大的檔案上去 server 一樣

其實不會,還記得之前說過 image 是一層一層疊加起來的嗎,現在這個 image 是 based on node:9.2.0,你在 push 的時候他只會上傳你新增的幾層,至於底下沒變更的那幾層就不需要 push,直接沿用 node:9.2.0

可以看到很多層都是 Mounted from library/node,真正需要 push 的只有最上面的兩層,所以還滿快的,push 完到 Docker Hub 上面就可以看到自己發佈的 image 了~因為是公開的所以別人也可以使用

但每次更新了 source code 或是 Dockerfile 之後,都要自己 build 再 push 上去,這樣很麻煩欸,有沒有工具可以自動幫我做這些事阿?

Automated Build

Automated Build 是 Docker Hub 提供的功能,他可以在你的 Github repo 有更新時就馬上根據 Dockerfile 幫你 build 一個新的 image,要使用這個功能首先到 Docker Hub 右上角點選 Create Automated Build

接著選 Github 或是 Bitbucket 告訴他你想幫哪個 repo 建立 Automated Build,我這邊是選我自己的 simple-express-server,因為 build 需要 Dockerfile,如果你現在手上沒有任何專案有 Dockerfile 的話,可以 fork 我的專案跟著做做看

給他一個 image 名字跟簡短的說明就可以了

設定觸發時機

新增完到 Build Settings 裡面看一下,現在有兩條規則:

  1. 每次 master 有新的 commit 時就自動 build 一個 image:latest
  2. 每次某個 branch 有新的 commit 時自動 build 一個 image:<branch name>

基本上不需要去改他,除非你要做更進階的設定

Push 新版本到 Github 上

Automated Build 已經設定完了,實際 push 一個新的 commit 到 Github 上,會看到 Build Details 裡面多了一個正在 build 的 image,之前說過只要有一樣的 Dockerfile,不管在哪裡 build 結果都會是一樣的,現在就是在 Docker 官方的主機上 Build

設定通知

如果在 build 的過程中發生了錯誤,那你應該會想收到通知吧?可以到通知這邊設定一下,發生錯誤的時候就會寄信跟你說

整個都設定完了之後就輕鬆了~以後只要有任何新的 code push 到 Github repo 上,Docker Hub 就會馬上 build 出一個新的 image,如果要在 server 上部屬的話直接從 Docker Hub 把它 pull 下來跑就可以了

題外話

雖然 Docker Hub 上的 Automated Build 看起來很猛很方便 XD,但也是有缺點的,在 Docker Hub 上最多只能有一個私人專案,超過就不能再建立了

但也不可能因此把私人或公司專案設公開,因為裡面有你的 code 還有 API_KEY 等等敏感資料,所以只能乖乖花錢買私人專案的額度,或是用其他免費的 docker registery 像是 canister 或是 treescale,如果考量安全性的話也可以自己架,但就會稍微麻煩一點

總結

這是系列文的第二篇,講了如何 push image 到 Docker Hub 上還有建立 Automated Build,如果是自己的專案想要方便部屬可以考慮用用看,或是要自己 build 一個像是 php + mysql 之類的環境回饋給社群也很不錯XD

下一篇講的是怎麼在 container 內跟本機共用檔案,有興趣的人歡迎追蹤我,謝謝大家~

 

 

資料來源:https://larrylu.blog/share-image-on-dockerhub-ccb7d9b26fa8

Docker 實戰系列(一):一步一步帶你 dockerize 你的應用

You can find the English version at Dockerize Your App: An Introduction to Docker.

想像一個情況,當你在本機開發完準備要部屬到自己的 server 上時,你發現 server 的系統不是你熟悉的 Ubuntu 而是 CentOS,除此之外你還需要自己安裝 php7、設定 MySQL 的帳號密碼跟架設 Apache,光想到要設定這些環境頭都痛了,這時候你就需要 Docker 了

Docker 可以幫你把 Ubuntu + php7 + MySQL + Apache 的環境跟你的程式碼打包起來,整包丟到 CentOS的 server 上去跑,不用很勉強的在不熟悉的 CentOS 上配置環境,弄個不好說不定還會影響到其他正在跑的程式

Docker 是什麼

Docker 是個輕量級的虛擬化技術,底層使用 cgroup、chroot、namespace 實作,可以把你的應用程式連同環境一起打包,部屬的時候就不用再擔心環境的問題

下圖的例子就是使用 Docker 將三個已經打包起來的程式跑在不同的 container(容器)中,每個 container 都是一個獨立的環境,可以跑不同的系統跟安裝不同的資料庫、編譯器等等,意思就是說你可以 A 專案用 php5.3,另外一個用 php7,完全不會衝突

Dockerize

所謂的 dockerize 就是把你的應用程式 Docker 化,把你的程式跟環境包成一個 image,部屬的時候就直接使用這個 image 不需要額外安裝其他東西

事前準備

你可以使用自己最近在做的 side project,也許是一個用 Django 寫的 api server,或是用 Node.js 寫的爬蟲等等,手邊沒有 side project 的話我有寫一個簡單的 simple-express-server,他會啟動一個 server 監聽 8080 port,到 127.0.0.1:8080 就可以看到 Hello World!

安裝 Docker

目前 Docker 有支援 Linux、Mac 跟 Windows,到 Get Docker 找到適合自己的版本,安裝完之後跑 docker version,有跑出版本就代表安裝成功了~

從 Docker Hub 上 pull image

Docker Hub 上有很多官方的 image 可以直接拿來用,所謂的 image 就是一個已經打包好的環境,譬如說 Debian 或是 Ubuntu + Node.js 等等,需要這個環境時就可以直接把這個 image pull 下來用。

使用 docker pull ubuntu 拿到最新的 ubuntu image,pull 的過程中會看到進度條

完成後跑 docker image ls 就能看到有一個 ubuntu 的 image

REPOSITORY    TAG        IMAGE ID         CREATED         SIZE
ubuntu latest 20c44cd7596f 2 weeks ago 123MB

接著 docker run -it ubuntu bash把 ubuntu 的 image 跑起來變成 container,-it 是為了讓我們進到這個 container 的 shell 下指令,進到 container 後跑跑看 cat /etc/*release,我這邊的版本是 16.04.3 LTS

到目前為止,我們已經可以在任何系統上用 Docker 跑 ubuntu 的環境了

很多人看到這裡可能會有點搞混 image 跟 container,說明一下,image 指的是已經打包好的環境,但是還沒有跑起來,就是一堆檔案而已,而 container 則是把 image 跑起來之後產生的 instance,他們之間的關係就像「程式碼」跟「跑起來的程式」,程式碼不跑就只是一堆檔案,但跑起來之後他就會變成一個真的在跑 process

開始 dockerize 你的應用程式

我們的終極目標是要把你的程式碼跟想要的環境打包起來,變成一個 image,之後不管到哪一台機器上,只要有裝 Docker 而且有這個 image 就可以把你的程式跑起來

雖然程式有千百種,dockerize 的過程也不盡相同,但大致上可以分成這 6 個步驟,接下來會以上面提供的 simple-express-server 作為範例,大家可以視情況調整成適合自己應用的樣子

Step 0 — 新增 Dockerfile

為了把環境跟程式碼包成一個 image,我們需要一個 Dockerfile 把打包的步驟寫在裡面,先在專案目錄下新增一個空檔案叫做 Dockerfile

simple-express-server
├── Dockerfile <-- 這裡
├── README.md
├── index.js
├── node_modules
└── package.json

Step 1 — 找到適合的 base image

Docker 的 image 是一層一層疊加上去的,所以我們需要先在 Docker Hub 上選擇一個 base image,然後再慢慢把它加工成我們要的樣子

因為我這個專案是用 Node.js 寫的,所以我需要一個已經裝好 Node.js 的環境,有兩個選擇:

  1. 直接用 node 作為我的 base image,裡面就已經有 Node.js 環境了
  2. ubuntu 當 base image,再參考 Installing 把 node 裝在 ubuntu 上

因為第一種作法比較簡單,這邊就直接使用 node,如果你是 python, golang 等等其他語言也都可以找到相對應的 image,決定 base image 後就在 Dockerfile 的第一行寫 FROM node:9.2.09.2.0 指的是我們使用的 node image 版本,如果想要最新版的的話也可以指定 node:latest

Step 2 — copy 原始碼

有了 Node.js 環境之後要把 code 也包進去,這邊使用 COPY 指令,把 index.jspackage.json 複製到 /app 資料夾裡面

Step 3 — 安裝 dependencies

現在環境都配置好了,code 也已經在裡面了,我們要做的事情就是切換到 /app 這個目錄安裝 dependencies

使用 WORKDIR 切換到 /app 目錄,再用 RUNnpm install && npm cache clean --force,清 npm cache 是為了讓 build 出來的 image 不要包含這些 cache,這樣 image 會小一點

如果是其他語言就把 npm install … 換成其他指令就可以了,像 python 可能就是 pip install …,有 cache 的話記得要清一下

Step 4 — 設定 initial command

現在環境、程式碼、dependencies 都準備好了,只剩把程式跑起來,這裡會用到 CMD 設定這個 image 被跑起來時的預設指令,對我這個程式來說要跑起來就是 node index.js,這樣就完成了 Dockerfile

Step 5 — build 出 image

完成後就可以開始 build image,在專案目錄下跑 docker build -t simple-express-server . 就會根據 Dockerfile build 出你的 image

build 完跑 docker image ls 可以看到多出一個 simple-express-server,這就是剛剛 build 出來的 image,裡面包含 node 的環境、程式碼還有 dependencies 跟預設啟動指令

REPOSITORY             TAG      IMAGE ID       CREATED        SIZE
simple-express-server latest dd05512eea91 2 minutes ago 677MB
ubuntu latest 20c44cd7596f 2 weeks ago 123MB

把 image 跑起來

有了 image 後可以 docker run -p 3000:8080 simple-express-server 把 image 跑起來,在 container 內跑的就是剛剛設定的預設指令 node index.js-p 3000:8080 則是把 container 內的 8080 port 跟外部的 3000 port 接通,如此一來只要用瀏覽器到 127.0.0.1:3000 就可以看到 Hello World!,這樣就完成 dockerize 了,現在你的電腦即便什麼都沒有只裝 docker 也可以把這個程式跑起來

跑在背景

如果照上面跑 docker run -p 3000:8080 <image> 的話會把終端機卡住,所以部屬的時候都會跑在背景,要跑在背景只要加一個 -d 就可以了,變成 docker run -d <image>,下指令後會得到一個 container ID,要看 log 的話可以跑 docker logs <container ID>

server 上沒有這個 image 怎麼辦

因為現在是在本機 build,遠端的 server 還沒有這個 image,如果要部屬必須先把 image 傳到遠端的機器,但這樣很麻煩,比較好的方式是把 Dockerfile 跟所有原始碼放在 git repo 裡面,直接在 server 上 build image,因為都是照 Dockerfile 裡面的內容跑,所以不管是在自己電腦還是 server 上 build 結果都是一樣的

 

 

資料來源:https://larrylu.blog/step-by-step-dockerize-your-app-ecd8940696f4

Docker - Dockerfile 指令教學,含範例解說

 

在前面介紹Docker的文章中,我們都是從Docer Hub中下載映像檔(Image)來建立Container,這些映像檔可能是軟體開發商所釋出,或者是第三方人士加值過的版本,這種做法的好處是很方便,但缺點則是映像檔包含的功能、工具或版本無法滿足自己的需求,此時利用 Dockerfile 客製化一個符合需求的映像檔,就是一個很好的解決方案。

Docker - Dockerfile 指令教學,含範例解說

在閱讀正文之前,建議要對Docker有所了解,新手可以先閱讀之前的二篇基本介紹,建立一點基本概念:
Docker – 新手入門,快速安裝與基本指令介紹
Docker Container 指令:Docker run & Docker exec

  • 是一個文字檔,由一行一行的指令所組成,用來描述這個映像檔應該長成怎麼樣
  • 利用Dockerfile可以建構/客製化出自己獨一無二的映像檔
  • 由於Dockerfile中可以清楚的知道映像檔的組成,因此,在安全性上會有所提升
  • 因為是純文字檔,所以檔案很小、很容易分享

Dockerfile 的組成

基本上Dockerfile是由一行一行的指令列所組成,一行指令對Image來說就是一層的資料層(Layer),一個Image就是靠這樣一層一層的資料累加上去,最後才編譯出自己想要的映像檔,就像蓋房子一樣。

常見Dockerfile內容中的指令如下:

# 開頭代表註解

文件中可使用#符號來進行註解。

FROM

基底映像檔,必需是「第一個」指令行,指定這個映像檔要以哪一個Image為基底來建構,格式為FROM <image>或FROM <image>:<tag>,範例如下:

FROM ubuntu:15.04 或
FROM ubuntu

MAINTAINER

映像檔維護者,把它想成是作者即可,格式為MAINTAINER <name>,範例如下:

MAINTAINER John 或
MAINTAINER john@myemail.com 或
MAINTAINER John john@myemail.com

LABEL

設定映像檔的Metadata資訊,例如:作者、EMail、映像檔的說明等,格式為:LABEL <key>=<value> <key>=<value> <key>=<value> …

簡單的來說就是以Key、Value來組成,它可以一行一組,也可以把全部合在一行撰寫,若多組合在一行,則每一組設定中間用空白鍵隔開即可,範例如下:

LABEL description="這是LABEL的範例" version="1.0" owner="靖技場"

和MAINTAINER相比,建議使用LABEL來設定會比較方便,另外,如果要查詢LABEL的資訊,則可以下docker inspect來查詢

RUN

執行指定的指令,每加一個RUN,就會在基底映像層加上一層資料層,以此類推,一層一層的建構起我們最後想要的映像檔,例如我們可以利用RUN來安裝套件,其格式分為二種:

  1. RUN <command>:以shell的形式執行,Linux的預設是/bin/sh -c,而Windows上的預設環境則是cmd /S /C
  2. RUN ["executable", "param1", "param2"]:以exec的形式執行指令,例如Linux上不想用預設的shell執行指令,那麼就可以透過RUN [“/bin/bash”, “-c”, “echo hello”]指定想要的shell

shell形式與exec形式有什麼不同呢?官方有提到

Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, RUN [ “echo”, “$HOME” ] will not do variable substitution on $HOME

意思是說exec執行的方式不會使用command shell,所以執行 RUN [ “echo”, “$HOME” ] 這樣的指令列, $HOME 這個變數是不會被替代(填入值)的,也就是直接輸出「$HOME」,但如果你想要有Shell處理的功能,則可以自行指定shell來達成:RUN [ “sh”, “-c”, “echo $HOME” ]

在使用RUN指令時,有以下注意要點:

  • 如果想要執行的指令很長,可以利用\符號來換行,比較容易閱讀
  • 使用exec形式執行時,必需使用JSON array的格式,因此,請使用雙引號
  • 每一個RUN就會新增一層資料層,為了減少不必要的資料層,可以利用&&來串連多個命令

簡單的RUN指令範例如下:

# install packages, only for demo
RUN mkdir -p /home/demo/docker
RUN ["apt-get", "install", "python3"]
RUN apt-get update && apt-get install -y --force-yes apache2 \
    firefox \
    php5

CMD

設定映像檔啟動為Container時預設要執行的指令,其指令共支援三種格式:

  1. CMD [“executable”,”param1″,”param2″]:exec形式,官方推薦此種方式
  2. CMD [“param1″,”param2”]:適用於有定義ENTRYPOINT指令的時候,CMD中的參數會做為ENTRYPOINT的預設參數
  3. CMD command param1 param2:會以shell的形式執行,預設是在「/bin/sh -c」下執行,適合在需要互動的指令時

使用CMD的注意事項:

  • Dockerfile中只能有一行CMD,若有多行CMD,則只有最後一行會生效
  • 若在建立Container時有帶執行的命令,則CMD的指令會被蓋掉,例如:執行docker run <image id>時,CMD所定義的指令會被執行,但當執行docker run <image id> bash時,Container就會執行bash,而原本CMD中定義的值就會覆蓋

CMD範例如下:

CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]
CMD [ "sh", "-c", "echo $HOME" ]
#作為ENTRYPOINT的參數使用
CMD ["Hello"]

ENTRYPOINT

和CMD一樣,用來設定映像檔啟動Container時要執行的指令,但不同的是,ENTRYPOINT一定會被執行,而不會有像CMD覆蓋的情況發生,支援二種格式:

  1. ENTRYPOINT [“executable”, “param1”, “param2”]:exec形式,官方推薦此種方式
  2. ENTRYPOINT command param1 param2:shell的形式

使用ENTRYPOINT的注意事項:

  • Dockerfile中只能有一行ENTRYPOINT,若有多行ENTRYPOINT,則只有最後一行會生效
  • 若在建立Container時有帶執行的命令,ENTRYPOINT的指令不會被覆蓋,也就是一定會執行
  • 如果想要覆蓋ENTRYPOINT的預設值,則在啟動Container時,可以加上「–entrypoint」的參數,例如:docker run –entrypoint

舉個實例,來看看ENTRYPOINT與CMD的關係,假設Dockerfile中的定義如下:

ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["World"]

如果是使用docker run -it <image>來啟動Container,那麼輸出的結果為「Hello World」,但如果是用docker run -it <image> Docker來啟動,則輸出結果會變成「Hello Docker」,因為CMD的值被覆蓋掉了

COPY

複製本地端的檔案/目錄到映像檔的指定位置中,其格式為:

  • COPY [–chown=<user>:<group>] <src>… <dest>
  • COPY [–chown=<user>:<group>] [“<src>”,… “<dest>”]

使用COPY的注意事項:

  • 指令的來源位置可以多個
  • 如果目的位置是目錄的話,記得最後要以/結尾,例如:/mypath/
  • 目的位置可以是絕對路徑或者相對於WORKDIR定義值的相對路徑
  • 若目的位置不存在,會自動建立

COPY的範例如下:

COPY file1.txt file2.js file3.json ./
COPY ["file1.txt", "file2.js", "file3.json" "./"]

ADD

和COPY一樣,可將本地端的檔案/目錄加到映像檔的指定位置內,其格式為:

  • ADD [–chown=<user>:<group>] <src>… <dest>
  • ADD [–chown=<user>:<group>] [“<src>”,… “<dest>”]

雖然ADD和CMD功能類似,但有二點最大的不同:

  1. ADD的來源路徑支援URL,也就是說可以加入遠端的檔案,COPY則不支援URL
  2. 若來源檔案是壓縮檔(副檔名為gzip、bzip2、xz),則使用ADD加入檔案時會自動解壓縮,而COPY不會

ADD的範例如下:

ADD file1.txt file2.js file3.json ./
# ENV_DEMO_VALUE 是用ENV指令所設定的環境變數
ADD https://www.google.com/demo.gzip $ENV_DEMO_VALUE

除非你有自動解壓的需求,不然一般建議會使用「COPY」來加入檔案

EXPOSE

宣告在映像檔中預設要使用(對外)的連接埠,格式如下:

  • EXPOSE <port> [<port>/<protocol>…]

EXPOSE預設的協定是TCP,但如果不是要TCP的話,可以自行指定,範例如下:

EXPOSE 80/tcp
EXPOSE 80/udp

使用EXPOSE所定義的連接埠並不會自動的啟用,而只是做提示的作用而已,要將連接埠啟用需要在執行docker run時,搭配-p或-P的參數來啟用。

小寫的-p可以自行指定與主機關聯的連接埠,例如:

docker run -p 80:80/tcp -p 80:80/udp demo

大寫的-P則會啟用所有EXPOSE所定義的連接埠,並動態(隨機)的關聯到主機的連接埠,例如:EXPOSE 80 可能隨機關聯到主機的 45123 連接埠,其範例如下:

docker run -P demo

ENV

設定環境變數,支援二種格式:

  1. ENV <key> <value>:Key後面的第一個空白鍵後會視為Value
  2. ENV <key>=<value> …:用等於符號來定義,每一組中間以空白鍵隔開,我個人比較喜歡這種形式,不容易搞混

ENV範例如下:

ENV demoPATH="/var/log" demoVer="1.0"
# 設置「/tmp/test.txt」給demoFile變數
ENV demoFile /tmp/test.txt

# 使用環境變數的例子,有沒有用大括號都可以
COPY debug.log ${demoPATH}
ADD $demoFile /foo

使用ENV設置環境變數後,在Dockerfile中其他的指令就可以利用,之後在建起來的Container裡也可以使用該變數

VOLUME

建立本機或來自其他容器的掛載點,指令格式如下:

  • VOLUME [“/data”]

VOLUME的值可以是JSON的Array格式,也可以是純文字,例如下以範例:

VOLUME ["/var/log/"] 或
VOLUME ["/demo1","/demo2"] 或
VOLUME /var/log 或
VOLUME /var/log /var/db

要特別注意的是使用VOLUME來定義掛載點時,是無法指定本機對應的目錄的,對應到哪個目錄是自動產生,我們可以透過docker inspect來查詢目錄資訊

WORKDIR

設定工作目錄,其格式如下:

  • WORKDIR /path/to/workdir

當設定WORKDIR後,Dockerfile中的RUN、CMD、ENTRYPOINT、COPY、ADD等指令就會在該工作目錄下執行,以下是官方的示範:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

在上面的範例中,pwd最後會在/a/b/c目錄下執行,如果目錄不存在,系統會幫忙自動建立

USER

指定運行Container時的用戶名稱或UID,其格式如下:

  • USER <user>[:<group>]
  • USER <UID>[:<gid>]

在定義了USER後,則Dockerfile中的RUN、CMD、ENTRYPOINT等指令便會以USER指定的用戶來執行,前提條件是該用戶必需是已存在的,否則指定會失敗,範例如下:

RUN groupadd -r tester && useradd -r -g tester tester
# 指定用戶名稱
USER tester

# 或使用UID來指定
USER 1000

ARG

設定在建置映像檔時可傳入的參數,即定義變數名稱以及變數的預設值,其格式為:

  • ARG <name>[=<default value>]

ARG和ENV的功能類似,都可以設定變數,但是ARG設定的值是供建置映像檔時使用(搭配docker build指令),在Container中是無法使用這些變數的,相反地,ENV的值則可以在Container中存取,例如ARG的定義如下:

ARG Param1
ARG Param2=somevalue

建構映像檔案,可利用–build-arg <varname>=<value>來指定參數,例如:

docker build --build-arg Param1=demo -t myimage:v1 .

在上面的例子中,我們在docker build中利用–build-arg <varname>=<value>參數將Param1的值變更為「demo」,而Param2的值並沒有指定,所以保留預設值「somevalue」

ONBUILD

若這個映像檔是作為其他映像檔的基底時,便需要定義ONBUILD指令,格式為:

  • ONBUILD [INSTRUCTION]

ONBUILD後面接的指令在自建的映像檔中不會被執行,只有當這個映像檔是作為其他映像檔的基底時才會被觸發,例如A映像檔的Dockerfile定義如下(假設名稱為A-Image):

...(以上略)
ONBUILD ADD . /home/tmp
ONBUILD mkdir -p /home/demo/docker
...(以下略)

此時如果B映像檔是以A映像檔為基底,則A映像檔中的ONBUILD指令就會被觸發,等於是以下指令:

# 以A映像檔為基底
FROM A-Image

# 觸發A映像檔ONBUILD的指令,即會自動執行下面二個指令行
# 下面二行指令不用自己加,Docker會自動去執行,這邊寫出只是方便做說明
ADD . /home/tmp
mkdir -p /home/demo/docker

如何使用Dockerfile ?

介紹了那麼多的指令,最終的目的就是利用Dockerfile來建立我們自己的映像檔,其指令為docker build,範例如下:

# 在目前目錄尋找Dockerfile或dockerfile
docker build -t myimage:v1 .

-t:Name and optionally a tag in the ‘name:tag’ format,指定映像檔名稱、標籤

在上面的範例中,是假設Dockerfile在當前目錄下,因此會以.結尾,若是在不同目錄,則可以直接接Dockerfile所在目錄或用-f來指定Dockerfile位置,例如:

# 後面接Dockerfile的所在目錄
docker build -t myimage:v2 ./docker
docker build -f /path/to/a/Dockerfile -t myimage:v3 .

用-f來指定Dockerfile的位置時,後面接的目錄(及其子目錄)需要能夠找到Dockerfile,否則會出現context錯誤

小結:Dockerfile裡面的指令也不少,但因篇幅的關係這邊沒有列出所有的指令,但應該也足夠滿足大部分的需求,想要更深入研究的話,建議可以參考官方的文件,但我個人認為最快的學習方法可以自己動手做做看,比較能夠體會每個指令到底有什麼功用

延伸閱讀:
Docker Compose – 安裝教學、指令用法及官方範例說明
Best practices for writing Dockerfiles
Dockerfile Reference

 

資料來源:https://www.jinnsblog.com/2018/12/docker-dockerfile-guide.html

Docker是什麼?使用Docker的好處與實戰實例

Docker是一個開源的容器化平台,可以用來打包、運行和分享應用程式。Docker通過容器化技術實現了應用程式的獨立性和可移植性,讓開發者和運維人員可以更加便捷地進行應用程式的開發、部署和運維。

容器技術的歷史與趨勢

過去,當我們想要在不同的環境下運行同一份程式碼,我們需要使用虛擬機技術。然而,虛擬機有一些固有的問題,比如需要的資源多、啟動慢、難以移動和複製等。容器技術則為解決這些問題提供了新的方向。

容器是一種軟體技術,可以將應用程式及其全部運行環境(包括文件系統、系統庫等)打包在一起,形成一個獨立、一致的運行單元。容器之間互相隔離,但共享同一個作業系統,每個容器都像一個輕量級的虛擬機。這種技術可以讓開發者在不同的系統和環境中,輕鬆地運行和管理他們的應用程式。

為什麼要使用Docker?

  1. 環境一致性:Docker可以將應用程式及其所有依賴項打包在一個容器中,確保了從開發到測試到生產的整個生命週期中,環境的一致性。這解決了“在我的機器上運行得好好的”這種常見問題。
  2. 輕量級和性能優越:與傳統的虛擬機相比,Docker容器不需要運行一整套操作系統,而是直接使用主機的操作系統,這使得容器變得非常輕量且啟動速度快。
  3. 應用程式隔離:每個容器都在其自己的空間中運行,並有其自己的網路和文件系統,互不干擾。這提供了額外的安全層,也使得各種應用程式可以在同一台機器上共存。
  4. 可移植性:由於容器包含了所有需要的依賴項,因此它可以在任何安裝了Docker的系統上運行,無論這個系統是物理機還是虛擬機,是在數據中心還是在雲端。
  5. 易於管理和擴展:Docker提供了豐富的工具和平台,用於管理容器、服務和集群,使應用程式的部署、擴展和運維變得簡單。

Docker的主要功能

  1. 容器創建和管理:Docker提供了創建、啟動、停止、移動和刪除容器的命令。
  2. 映像創建和分發:Docker可以從容器創建映像,並將映像分發到其他機器上。這是實現快速應用程式部署和擴展的基礎。
  3. 版本控制:Docker支持映像的版本控制。開發者可以追蹤映像的改變,並在需要的時候回滾到先前的版本。
  4. 資源隔離:Docker使用Linux的cgroups技術來隔離容器的資源,比如CPU、記憶體和網路。
  5. 資源整合:Docker可以將主機的資源如磁盤、網路和文件系統整合到容器中,使容器可以像真實的獨立系統一樣運行。

如何使用Docker?

使用Docker可以分為三個步驟:構建映像、運行容器和分享映像。首先,需要構建一個Docker映像,包括應用程式及其依賴的庫和環境等。然後,運行映像可以通過命令行、Docker Compose等方式實現。最後,可以將構建好的Docker映像分享給其他使用者,讓他們可以快速地部署和運行應用程式。

Docker 是什麼?實戰手札帶你認識 Docker

何時應該使用Docker?

Docker適用於需要開發、部署和運維應用程式的場景,尤其是在多平台、多環境、多依賴等複雜場景下。使用Docker可以提高開發效率、簡化部署流程、減少運維成本、提高應用程式的可靠性和可移植性等。

如何使用Docker

使用Docker很簡單。以下是使用Docker的基本步驟:

  1. 安裝Docker:首先,你需要安裝Docker並在電腦上運行Docker服務。安裝過程可以在Docker的官方網站上找到詳細步驟,並且也有針對不同作業系統的安裝檔案。

根據您的操作系統,選擇合適的Docker安裝方法:

Docker基本概念

  • 映像檔(Image):包含應用程式和其依賴項的打包檔案,可以從Docker Hub下載或自行創建。
  • 容器(Container):映像檔的運行實例,可以創建、啟動、停止或刪除。
  • 倉庫(Repository):存儲映像檔的地方,例如Docker Hub。

Docker實戰:創建和運行容器

我們將一步步地帶領您完成使用Docker開發、部署和運行一個簡單的JavaScript Web應用程式,這裡我們將使用Node.js和Express框架。

  1. 創建Dockerfile

首先,創建一個新的目錄並進入該目錄:

mkdir js-web-app && cd js-web-app

在此目錄中創建一個名為Dockerfile的檔案,並使用以下內容:

# 使用官方Node.js映像檔作為基礎
FROM node:14

# 設置工作目錄
WORKDIR /app

# 將應用程式所需的套件安裝到容器中
COPY package*.json ./
RUN npm install

# 複製應用程式程式碼到容器中
COPY . .

# 暴露容器的端口,供外部訪問
EXPOSE 3000

# 啟動應用程式
CMD ["npm", "start"]

3. 構建映像檔

js-web-app目錄中,創建一個簡單的JavaScript Web應用程式。首先創建package.json檔案:

{
  "name": "js-web-app",
  "version": "1.0.0",
  "description": "A simple JavaScript web app",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  }
}

接下來,創建app.js檔案:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send('Hello, Docker!');
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

js-web-app目錄中運行以下命令構建Docker映像檔:

docker build -t js-web-app .
``

4. 運行容器

使用剛剛構建好的映像檔運行容器:

docker run -d -p 3000:3000 --name my-js-web-app js-web-app

這個命令將會運行一個名為my-js-web-app的容器,並將容器的3000端口映射到主機的3000端口。

5. 訪問應用程式

在瀏覽器中訪問http://localhost:3000,您應該可以看到顯示 “Hello, Docker!” 的頁面。

6. 部署至雲端

將您的應用程式部署到雲端(例如:AWS, Google Cloud, Azure等),首先需要將您的Docker映像檔推送到容器倉庫,例如Docker Hub。

  1. 使用Docker命令登錄Docker Hub(如果您還沒有Docker Hub帳戶,請先註冊一個):
docker login
  1. 為映像檔添加標籤,使用您的Docker Hub用戶名和新的倉庫名稱:
docker tag js-web-app <YOUR_DOCKER_HUB_USERNAME>/js-web-app
  1. 推送映像檔到Docker Hub:
docker push <YOUR_DOCKER_HUB_USERNAME>/js-web-app

接下來,您可以根據您選擇的雲平台,遵循相應的指南部署您的應用程式。例如,對於AWS,您可以選擇使用Amazon ECS來部署和運行您的Docker容器。

Docker的管理工具和平台

在使用Docker時,除了Docker自身提供的命令行工具外,還有許多第三方工具和平台可以幫助我們更方便地管理和使用Docker。以下是幾個常用的推薦:

  1. Docker Compose:這是Docker官方提供的一個工具,可以讓使用者用YAML檔案來定義多個容器的應用程式,並管理它們的生命週期。
  2. Docker Swarm:這是Docker的內建集群管理和編排功能,可以讓使用者管理一群Docker主機,並分發服務到這些主機上。
  3. Kubernetes:這是一個開源的容器編排平台,支援Docker和其他容器技術。它提供了高度自動化的部署、擴展和管理應用程式的功能。
  4. Portainer:這是一個開源的Docker管理工具,提供了一個用戶友好的圖形化介面,讓使用者可以方便地管理Docker容器、映像、網路等。

我們一步步地帶領您完成使用Docker開發、部署和運行一個簡單的JavaScript Web應用程式。Docker簡化了開發、部署和運行應用程式的過程,使得應用程式在不同環境中的運行更加一致。希望這個教學能夠對你有所幫助。

 

 

資料來源:https://tw.alphacamp.co/blog/docker