通過 Docker 化一個部落格網站來開啟我們的 Docker 之旅
這篇文章包含 Docker 的基本概念,以及如何通過建立一個定製的 Dockerfile 來Docker 化(Dockerize)一個應用。
Docker 是一個過去兩年來從某個 idea 中孕育而生的有趣技術,公司組織們用它在世界上每個角落來部署應用。在今天的文章中,我將講述如何通過“Docker 化(Dockerize)”一個現有的應用,來開始我們的 Docker 之旅。這裡提到的應用指的就是這個部落格!
什麼是 Docker?
當我們開始學習 Docker 基本概念時,讓我們先去搞清楚什麼是 Docker 以及它為什麼這麼流行。Docker 是一個作業系統容器管理工具,它通過將應用打包在作業系統容器中,來方便我們管理和部署應用。
容器 vs. 虛擬機器
容器和虛擬機器並不完全相似,它是另外一種提供作業系統虛擬化的方式。它和標準的虛擬機器還是有所不同。
標準的虛擬機器一般會包括一個完整的作業系統、作業系統軟體包、最後還有一至兩個應用。這都得益於為虛擬機器提供硬體虛擬化的管理程式。這樣一來,一個單一的伺服器就可以將許多獨立的作業系統作為虛擬客戶機執行了。
容器和虛擬機器很相似,它們都支援在單一的伺服器上執行多個操作環境,只是,在容器中,這些環境並不是一個個完整的作業系統。容器一般只包含必要的作業系統軟體包和一些應用。它們通常不會包含一個完整的作業系統或者硬體的虛擬化。這也意味著容器比傳統的虛擬機器開銷更少。
容器和虛擬機器常被誤認為是兩種對立的技術。虛擬機器採用一個物理伺服器來提供全功能的操作環境,該環境會和其餘虛擬機器一起共享這些物理資源。容器一般用來隔離一個單一主機上執行的應用程式,以保證隔離後的程式之間不能相互影響。事實上,容器和 BSD Jails 以及 chroot 程式的相似度,超過了和完整虛擬機器的相似度。
Docker 在容器之上提供了什麼
Docker 本身不是一個容器執行環境,事實上,只是一個與具體實現無關的容器技術,Docker 正在努力支援 Solaris Zones 和 BSD Jails。Docker 提供了一種管理、打包和部署容器的方式。雖然一定程度上,虛擬機器多多少少擁有這些類似的功能,但虛擬機器並沒有完整擁有絕大多數的容器功能,即使擁有,這些功能用起來都並沒有 Docker 來的方便或那麼完整。
現在,我們應該知道 Docker 是什麼了,然後,我們將從安裝 Docker,並部署一個公開的預構建好的容器開始,學習 Docker 是如何工作的。
從安裝開始
預設情況下,Docker 並不會自動被安裝在您的計算機中,所以,第一步就是安裝 Docker 軟體包;我們的教學機器系統是 Ubuntu 14.0.4,所以,我們將使用 Apt 軟體包管理器,來執行安裝操作。
# apt-get install docker.io Reading package lists... Done Building dependency tree Reading state information... Done The following extra packages will be installed: aufs-tools cgroup-lite git git-man liberror-perl Suggested packages: btrfs-tools debootstrap lxc rinse git-daemon-run git-daemon-sysvinit git-doc git-el git-email git-gui gitk gitweb git-arch git-bzr git-cvs git-mediawiki git-svn The following NEW packages will be installed: aufs-tools cgroup-lite docker.io git git-man liberror-perl 0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded. Need to get 7,553 kB of archives. After this operation, 46.6 MB of additional disk space will be used. Do you want to continue? [Y/n] y
為了檢查當前是否有容器執行,我們可以執行docker命令,加上ps選項
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
docker命令中的ps功能類似於 Linux 的ps命令。它將顯示可找到的 Docker 容器及其狀態。由於我們並沒有啟動任何 Docker 容器,所以命令沒有顯示任何正在執行的容器。
部署一個預構建好的 nginx Docker 容器
我比較喜歡的 Docker 特性之一就是 Docker 部署預先構建好的容器的方式,就像yum和apt-get部署包一樣。為了更好地解釋,我們來部署一個執行著 nginx web 伺服器的預構建容器。我們可以繼續使用docker命令,這次選擇run選項。
# docker run -d nginx Unable to find image 'nginx' locally Pulling repository nginx 5c82215b03d1: Download complete e2a4fb18da48: Download complete 58016a5acc80: Download complete 657abfa43d82: Download complete dcb2fe003d16: Download complete c79a417d7c6f: Download complete abb90243122c: Download complete d6137c9e2964: Download complete 85e566ddc7ef: Download complete 69f100eb42b5: Download complete cd720b803060: Download complete 7cc81e9a118a: Download complete
docker命令的run選項,用來通知 Docker 去尋找一個指定的 Docker 映象,然後啟動執行著該映象的容器。預設情況下,Docker 容器執行在前臺,這意味著當你執行docker run命令的時候,你的 shell 會被繫結到容器的控制檯以及執行在容器中的程式。為了能在後臺執行該 Docker 容器,我們使用了-d (detach)標誌。
再次執行docker ps命令,可以看到 nginx 容器正在執行。
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f6d31ab01fc9 nginx:latest nginx -g 'daemon off 4 seconds ago Up 3 seconds 443/tcp, 80/tcp desperate_lalande
從上面的輸出資訊中,我們可以看到正在執行的名為desperate_lalande的容器,它是由nginx:latest image(LCTT 譯註: nginx 最新版本的映象)構建而來得。
Docker 映象
映象是 Docker 的核心特徵之一,類似於虛擬機器映象。和虛擬機器映象一樣,Docker 映象是一個被儲存並打包的容器。當然,Docker 不只是建立映象,它還可以通過 Docker 倉庫釋出這些映象,Docker 倉庫和軟體包倉庫的概念差不多,它讓 Docker 能夠模仿yum部署軟體包的方式來部署映象。為了更好地理解這是怎麼工作的,我們來回顧docker run執行後的輸出。
# docker run -d nginx Unable to find image 'nginx' locally
我們可以看到第一條資訊是,Docker 不能在本地找到名叫 nginx 的映象。這是因為當我們執行docker run命令時,告訴 Docker 執行一個基於 nginx 映象的容器。既然 Docker 要啟動一個基於特定映象的容器,那麼 Docker 首先需要找到那個指定映象。在檢查遠端倉庫之前,Docker 首先檢查本地是否存在指定名稱的本地映象。
因為系統是嶄新的,不存在 nginx 映象,Docker 將選擇從 Docker 倉庫下載之。
Pulling repository nginx 5c82215b03d1: Download complete e2a4fb18da48: Download complete 58016a5acc80: Download complete 657abfa43d82: Download complete dcb2fe003d16: Download complete c79a417d7c6f: Download complete abb90243122c: Download complete d6137c9e2964: Download complete 85e566ddc7ef: Download complete 69f100eb42b5: Download complete cd720b803060: Download complete 7cc81e9a118a: Download complete
這就是第二部分輸出資訊顯示給我們的內容。預設情況下,Docker 會使用 Docker Hub 倉庫,該倉庫由 Docker 公司維護。
和 Github 一樣,在 Docker Hub 建立公共倉庫是免費的,私人倉庫就需要繳納費用了。當然,部署你自己的 Docker 倉庫也是可以的,事實上只需要簡單地執行docker run registry命令就行了。但在這篇文章中,我們的重點將不是講解如何部署一個定製的註冊服務。
關閉並移除容器
在我們繼續構建定製容器之前,我們先清理一下 Docker 環境,我們將關閉先前的容器,並移除它。
我們利用docker命令和run選項執行一個容器,所以,為了停止同一個容器,我們簡單地在執行docker命令時,使用kill選項,並指定容器名。
# docker kill desperate_lalande desperate_lalande
當我們再次執行docker ps,就不再有容器執行了
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
但是,此時,我們這是停止了容器;雖然它不再執行,但仍然存在。預設情況下,docker ps只會顯示正在執行的容器,如果我們附加-a (all) 標識,它會顯示所有執行和未執行的容器。
# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f6d31ab01fc9 5c82215b03d1 nginx -g 'daemon off 4 weeks ago Exited (-1) About a minute ago desperate_lalande
為了能完整地移除容器,我們在用docker命令時,附加rm選項。
# docker rm desperate_lalande desperate_lalande
雖然容器被移除了;但是我們仍擁有可用的nginx映象(LCTT 譯註:映象快取)。如果我們重新執行docker run -d nginx,Docker 就無需再次拉取 nginx 映象即可啟動容器。這是因為我們本地系統中已經儲存了一個副本。
為了列出系統中所有的本地映象,我們執行docker命令,附加images選項。
# docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE nginx latest 9fab4090484a 5 days ago 132.8 MB
構建我們自己的映象
截至目前,我們已經使用了一些基礎的 Docker 命令來啟動、停止和移除一個預構建好的普通映象。為了“Docker 化(Dockerize)”這篇部落格,我們需要構建我們自己的映象,也就是建立一個 Dockerfile。
在大多數虛擬機器環境中,如果你想建立一個機器映象,首先,你需要建立一個新的虛擬機器、安裝作業系統、安裝應用,最後將其轉換為一個模板或者映象。但在 Docker 中,所有這些步驟都可以通過 Dockerfile 實現全自動。Dockerfile 是向 Docker 提供構建指令去構建定製映象的方式。在這一章節,我們將編寫能用來部署這個部落格的定製 Dockerfile。
理解應用
我們開始構建 Dockerfile 之前,第一步要搞明白,我們需要哪些東西來部署這個部落格。
這個部落格本質上是由一個靜態站點生成器生成的靜態 HTML 頁面,這個生成器是我編寫的,名為 hamerkop。這個生成器很簡單,它所做的就是生成該部落格站點。所有的程式碼和原始檔都被我放在了一個公共的 Github 倉庫。為了部署這篇部落格,我們要先從 Github 倉庫把這些內容拉取下來,然後安裝 Python 和一些 Python 模組,最後執行hamerkop應用。我們還需要安裝 nginx,來執行生成後的內容。
截止目前,這些還是一個簡單的 Dockerfile,但它卻給我們展示了相當多的 Dockerfile 語法)。我們需要克隆 Github 倉庫,然後使用你最喜歡的編輯器編寫 Dockerfile,我選擇vi。
# git clone https://github.com/madflojo/blog.git Cloning into 'blog'... remote: Counting objects: 622, done. remote: Total 622 (delta 0), reused 0 (delta 0), pack-reused 622 Receiving objects: 100% (622/622), 14.80 MiB | 1.06 MiB/s, done. Resolving deltas: 100% (242/242), done. Checking connectivity... done. # cd blog/ # vi Dockerfile
FROM – 繼承一個 Docker 映象
第一條 Dockerfile 指令是FROM指令。這將指定一個現存的映象作為我們的基礎映象。這也從根本上給我們提供了繼承其他 Docker 映象的途徑。在本例中,我們還是從剛剛我們使用的 nginx 開始,如果我們想從頭開始,我們可以通過指定ubuntu:latest來使用 Ubuntu Docker 映象。
## Dockerfile that generates an instance of http://bencane.com FROM nginx:latest MAINTAINER Benjamin Cane <ben@bencane.com>
除了FROM指令,我還使用了MAINTAINER,它用來顯示 Dockerfile 的作者。
Docker 支援使用#作為註釋,我將經常使用該語法,來解釋 Dockerfile 的部分內容。
執行一次測試構建
因為我們繼承了 nginx Docker映象,我們現在的 Dockerfile 也就包括了用來構建 nginx 映象的 Dockerfile 中所有指令。這意味著,此時我們可以從該 Dockerfile 中構建出一個 Docker 映象,然後以該映象執行一個容器。雖然,最終的映象和 nginx 映象本質上是一樣的,但是我們這次是通過構建 Dockerfile 的形式,然後我們將講解 Docker 構建映象的過程。
想要從 Dockerfile 構建映象,我們只需要在執行 docker 命令的時候,加上 build 選項。
# docker build -t blog /root/blog Sending build context to Docker daemon 23.6 MB Sending build context to Docker daemon Step 0 : FROM nginx:latest ---> 9fab4090484a Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com> ---> Running in c97f36450343 ---> 60a44f78d194 Removing intermediate container c97f36450343 Successfully built 60a44f78d194
上面的例子,我們使用了-t (tag)標識給映象新增“blog”的標籤。實質上我們就是在給映象命名,如果我們不指定標籤,就只能通過 Docker 分配的 Image ID 來訪問映象了。本例中,從 Docker 構建成功的資訊可以看出,Image ID值為 60a44f78d194。
除了-t標識外,我還指定了目錄/root/blog。該目錄被稱作“構建目錄”,它將包含 Dockerfile,以及其它需要構建該容器的檔案。
現在我們構建成功了,下面我們開始定製該映象。
使用 RUN 來執行 apt-get
用來生成 HTML 頁面的靜態站點生成器是用 Python 語言編寫的,所以,在 Dockerfile 中需要做的第一件定製任務是安裝 Python。我們將使用 Apt 軟體包管理器來安裝 Python 軟體包,這意味著在 Dockerfile 中我們要指定執行apt-get update和apt-get install python-dev;為了完成這一點,我們可以使用RUN指令。
## Dockerfile that generates an instance of http://bencane.com FROM nginx:latest MAINTAINER Benjamin Cane <ben@bencane.com> ## Install python and pip RUN apt-get update RUN apt-get install -y python-dev python-pip
如上所示,我們只是簡單地告知 Docker 構建映象的時候,要去執行指定的apt-get命令。比較有趣的是,這些命令只會在該容器的上下文中執行。這意味著,即使在容器中安裝了python-dev和python-pip,但主機本身並沒有安裝這些。說的更簡單點,pip命令將只在容器中執行,出了容器,pip命令不存在。
還有一點比較重要的是,Docker 構建過程中不接受使用者輸入。這說明任何被RUN指令執行的命令必須在沒有使用者輸入的時候完成。由於很多應用在安裝的過程中需要使用者的輸入資訊,所以這增加了一點難度。不過我們例子中,RUN命令執行的命令都不需要使用者輸入。
安裝 Python 模組
Python 安裝完畢後,我們現在需要安裝 Python 模組。如果在 Docker 外做這些事,我們通常使用pip命令,然後參考我的部落格 Git 倉庫中名叫requirements.txt的檔案。在之前的步驟中,我們已經使用Git命令成功地將 Github 倉庫“克隆”到了/root/blog目錄;這個目錄碰巧也是我們建立Dockerfile的目錄。這很重要,因為這意味著 Docker 在構建過程中可以訪問這個 Git 倉庫中的內容。
當我們執行構建後,Docker 將構建的上下文環境設定為指定的“構建目錄”。這意味著目錄中的所有檔案都可以在構建過程中被使用,目錄之外的檔案(構建環境之外)是不能訪問的。
為了能安裝所需的 Python 模組,我們需要將requirements.txt從構建目錄拷貝到容器中。我們可以在Dockerfile中使用COPY指令完成這一需求。
## Dockerfile that generates an instance of http://bencane.com FROM nginx:latest MAINTAINER Benjamin Cane <ben@bencane.com> ## Install python and pip RUN apt-get update RUN apt-get install -y python-dev python-pip ## Create a directory for required files RUN mkdir -p /build/ ## Add requirements file and run pip COPY requirements.txt /build/ RUN pip install -r /build/requirements.txt
在Dockerfile中,我們增加了3條指令。第一條指令使用RUN在容器中建立了/build/目錄。該目錄用來拷貝生成靜態 HTML 頁面所需的一切應用檔案。第二條指令是COPY指令,它將requirements.txt從“構建目錄”(/root/blog)拷貝到容器中的/build/目錄。第三條使用RUN指令來執行pip命令;安裝requirements.txt檔案中指定的所有模組。
當構建定製映象時,COPY是條重要的指令。如果在 Dockerfile 中不指定拷貝檔案,Docker 映象將不會包含requirements.txt 這個檔案。在 Docker 容器中,所有東西都是隔離的,除非在 Dockerfile 中指定執行,否則容器中不會包括所需的依賴。
重新執行構建
現在,我們讓 Docker 執行了一些定製任務,現在我們嘗試另一次 blog 映象的構建。
# docker build -t blog /root/blog Sending build context to Docker daemon 19.52 MB Sending build context to Docker daemon Step 0 : FROM nginx:latest ---> 9fab4090484a Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com> ---> Using cache ---> 8e0f1899d1eb Step 2 : RUN apt-get update ---> Using cache ---> 78b36ef1a1a2 Step 3 : RUN apt-get install -y python-dev python-pip ---> Using cache ---> ef4f9382658a Step 4 : RUN mkdir -p /build/ ---> Running in bde05cf1e8fe ---> f4b66e09fa61 Removing intermediate container bde05cf1e8fe Step 5 : COPY requirements.txt /build/ ---> cef11c3fb97c Removing intermediate container 9aa8ff43f4b0 Step 6 : RUN pip install -r /build/requirements.txt ---> Running in c50b15ddd8b1 Downloading/unpacking jinja2 (from -r /build/requirements.txt (line 1)) Downloading/unpacking PyYaml (from -r /build/requirements.txt (line 2)) <truncated to reduce noise> Successfully installed jinja2 PyYaml mistune markdown MarkupSafe Cleaning up... ---> abab55c20962 Removing intermediate container c50b15ddd8b1 Successfully built abab55c20962
上述輸出所示,我們可以看到構建成功了,我們還可以看到另外一個有趣的資訊—> Using cache。這條資訊告訴我們,Docker 在構建該映象時使用了它的構建快取。
Docker 構建快取
當 Docker 構建映象時,它不僅僅構建一個單獨的映象;事實上,在構建過程中,它會構建許多映象。從上面的輸出資訊可以看出,在每一“步”執行後,Docker 都在建立新的映象。
Step 5 : COPY requirements.txt /build/ ---> cef11c3fb97c
上面片段的最後一行可以看出,Docker 在告訴我們它在建立一個新映象,因為它列印了Image ID : cef11c3fb97c。這種方式有用之處在於,Docker能在隨後構建這個 blog 映象時將這些映象作為快取使用。這很有用處,因為這樣, Docker 就能加速同一個容器中新構建任務的構建流程。從上面的例子中,我們可以看出,Docker 沒有重新安裝python-dev和python-pip包,Docker 則使用了快取映象。但是由於 Docker 並沒有找到執行mkdir命令的構建快取,隨後的步驟就被一一執行了。
Docker 構建快取一定程度上是福音,但有時也是噩夢。這是因為決定使用快取或者重新執行指令的因素很少。比如,如果requirements.txt檔案發生了修改,Docker 會在構建時檢測到該變化,然後 Docker 會重新執行該執行那個點往後的所有指令。這得益於 Docker 能檢視requirements.txt的檔案內容。但是,apt-get命令的執行就是另一回事了。如果提供 Python 軟體包的 Apt 倉庫包含了一個更新的 python-pip 包;Docker 不會檢測到這個變化,轉而去使用構建快取。這會導致之前舊版本的包將被安裝。雖然對python-pip來說,這不是主要的問題,但對使用了存在某個致命攻擊缺陷的軟體包快取來說,這是個大問題。
出於這個原因,拋棄 Docker 快取,定期地重新構建映象是有好處的。這時,當我們執行 Docker 構建時,我簡單地指定–no-cache=True即可。
部署部落格的剩餘部分
Python 軟體包和模組安裝後,接下來我們將拷貝需要用到的應用檔案,然後執行hamerkop應用。我們只需要使用更多的COPY 和 RUN指令就可完成。
## Dockerfile that generates an instance of http://bencane.com FROM nginx:latest MAINTAINER Benjamin Cane <ben@bencane.com> ## Install python and pip RUN apt-get update RUN apt-get install -y python-dev python-pip ## Create a directory for required files RUN mkdir -p /build/ ## Add requirements file and run pip COPY requirements.txt /build/ RUN pip install -r /build/requirements.txt ## Add blog code nd required files COPY static /build/static COPY templates /build/templates COPY hamerkop /build/ COPY config.yml /build/ COPY articles /build/articles ## Run Generator RUN /build/hamerkop -c /build/config.yml
現在我們已經寫出了剩餘的構建指令,我們再次執行另一次構建,並確保映象構建成功。
# docker build -t blog /root/blog/ Sending build context to Docker daemon 19.52 MB Sending build context to Docker daemon Step 0 : FROM nginx:latest ---> 9fab4090484a Step 1 : MAINTAINER Benjamin Cane <ben@bencane.com> ---> Using cache ---> 8e0f1899d1eb Step 2 : RUN apt-get update ---> Using cache ---> 78b36ef1a1a2 Step 3 : RUN apt-get install -y python-dev python-pip ---> Using cache ---> ef4f9382658a Step 4 : RUN mkdir -p /build/ ---> Using cache ---> f4b66e09fa61 Step 5 : COPY requirements.txt /build/ ---> Using cache ---> cef11c3fb97c Step 6 : RUN pip install -r /build/requirements.txt ---> Using cache ---> abab55c20962 Step 7 : COPY static /build/static ---> 15cb91531038 Removing intermediate container d478b42b7906 Step 8 : COPY templates /build/templates ---> ecded5d1a52e Removing intermediate container ac2390607e9f Step 9 : COPY hamerkop /build/ ---> 59efd1ca1771 Removing intermediate container b5fbf7e817b7 Step 10 : COPY config.yml /build/ ---> bfa3db6c05b7 Removing intermediate container 1aebef300933 Step 11 : COPY articles /build/articles ---> 6b61cc9dde27 Removing intermediate container be78d0eb1213 Step 12 : RUN /build/hamerkop -c /build/config.yml ---> Running in fbc0b5e574c5 Successfully created file /usr/share/nginx/html//2011/06/25/checking-the-number-of-lwp-threads-in-linux Successfully created file /usr/share/nginx/html//2011/06/checking-the-number-of-lwp-threads-in-linux <truncated to reduce noise> Successfully created file /usr/share/nginx/html//archive.html Successfully created file /usr/share/nginx/html//sitemap.xml ---> 3b25263113e1 Removing intermediate container fbc0b5e574c5 Successfully built 3b25263113e1
執行定製的容器
成功的一次構建後,我們現在就可以通過執行docker命令和run選項來執行我們定製的容器,和之前我們啟動 nginx 容器一樣。
# docker run -d -p 80:80 --name=blog blog 5f6c7a2217dcdc0da8af05225c4d1294e3e6bb28a41ea898a1c63fb821989ba1
我們這次又使用了-d (detach)標識來讓Docker在後臺執行。但是,我們也可以看到兩個新標識。第一個新標識是–name,這用來給容器指定一個使用者名稱稱。之前的例子,我們沒有指定名稱,因為 Docker 隨機幫我們生成了一個。第二個新標識是-p,這個標識允許使用者從主機對映一個埠到容器中的一個埠。
之前我們使用的基礎 nginx 映象分配了80埠給 HTTP 服務。預設情況下,容器內的埠通道並沒有繫結到主機系統。為了讓外部系統能訪問容器內部埠,我們必須使用-p標識將主機埠對映到容器內部埠。上面的命令,我們通過-p 80:80語法將主機80埠對映到容器內部的80埠。
經過上面的命令,我們的容器看起來成功啟動了,我們可以通過執行docker ps核實。
# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d264c7ef92bd blog:latest nginx -g 'daemon off 3 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:80->80/tcp blog
總結
截止目前,我們擁有了一個執行中的定製 Docker 容器。雖然在這篇文章中,我們只接觸了一些 Dockerfile 指令用法,但是我們還是要學習所有的指令。我們可以檢查 Docker’s reference page 來獲取所有的 Dockerfile 指令用法,那裡對指令的用法說明得很詳細。
另一個比較好的資源是 Dockerfile Best Practices page,它有許多構建定製 Dockerfile 的最佳練習。有些技巧非常有用,比如戰略性地組織好 Dockerfile 中的命令。上面的例子中,我們將articles目錄的COPY指令作為 Dockerfile 中最後的COPY指令。這是因為articles目錄會經常變動。所以,將那些經常變化的指令儘可能地放在最後面的位置,來最優化那些可以被快取的步驟。
通過這篇文章,我們涉及瞭如何執行一個預構建的容器,以及如何構建,然後部署定製容器。雖然關於 Docker 你還有許多需要繼續學習的地方,但我想這篇文章給了你如何繼續開始的好建議。當然,如果你認為還有一些需要繼續補充的內容,在下面評論即可。
相關文章
- 透過 Docker 化一個部落格網站來開啟我們的 Docker 之旅Docker網站
- 我的個人部落格搭建之旅
- docker通過commit命令提交一個映象DockerMIT
- 我的網站之旅 (一)構思網站
- 利用docker快速搭建hexo部落格DockerHexo
- 使用Docker搭建Chirpy部落格Docker
- 通過做一個基於Node的微伺服器來學習Docker伺服器Docker
- 部落格網站網站
- Docker一個漏洞讓駭客侵入刪除了資料庫 | NewsBlur 部落格Docker資料庫
- 使用 github 和 Deno Deploy 搭建一個部落格網站Github網站
- Docker安全:通過Docker提升許可權Docker
- 通過docker部署lnmpDockerLNMP
- 分享一個我的 Django 部落格專案Django
- 通過面試題,讓我們來了解Collection面試題
- 使用docker搭建nginx掛載hexo部落格DockerNginxHexo
- 個人部落格如何搭建 用什麼系統好?學網站建設從開發一個部落格開始網站
- 開發人員應關注的20個jQuery網站/部落格jQuery網站
- 玩遍部落格網站,我整理了 Hexo 及其流行的風格主題網站Hexo
- 開通ITPub的部落格啦!
- 著名部落格網站TechCrunch挖來福克斯高管掌舵網站
- PHP 開發者的 Docker 之旅PHPDocker
- 我的Docker之旅,文章目錄,歡迎關注Docker
- cxword網站加部落格網站
- 如何通過gzip和nginx來提高網站開啟速度及整體效能Nginx網站
- 通過 docker-compose 一鍵部署一個微服務專案Docker微服務
- Docker最全教程之使用PHP搭建個人部落格站點(二十二)DockerPHP
- 搭建我的第一個Docker應用棧Docker
- 玩遍部落格網站,我整理了全套的建站技術棧網站
- Sql Server之旅——第一站 那些給我們帶來福利的系統檢視SQLServer
- 開通ITPub部落格了!
- 安裝Docker 及部署 Wordpress 部落格系統Docker
- Docker部署Halo部落格並配置SSL證書Docker
- 通過執行一個tomcat容器來記錄下初學docker常用的幾個命令---映象篇TomcatDocker
- 通過執行一個tomcat容器來記錄下初學docker常用的幾個命令---容器篇TomcatDocker
- 少寫一個`var`是如何毀掉我們網站的網站
- VuePress 部落格優化之開啟 HTTPSVue優化HTTP
- 我們的移動混合開發之旅
- docker(二十三):docker通過docker-compose部署redmine服務Docker