全文采用的是阿里雲的ESC服務器,系統是CentOS 7
示例項目是NodeJS編寫,本文主要是Docker的使用,在文章前2/3都是Docker命令介紹,最后我們會完成一個自動化的示例。
准備
注冊賬號
-
GitHub賬號
發布項目到GitHub
-
Travis-CI賬號
監聽GitHub上項目改變,將其打包發布到DockerHub
-
DockerHub賬號
Travis-CI將項目發布到DokcerHub時需要登陸DockerHub賬號
以上賬號自行注冊
關於如何讓Travis-CI監聽到GitHub上項目的改變,請參考這篇文章
安裝環境
-
Git環境
-
Docker環境
安裝請參考官方文檔
安裝完成后,運行下面的命令,驗證是否安裝成功。
$ docker version # 或者 $ docker info
Docker 需要用戶具有 sudo 權限,為了避免每次命令都輸入
sudo
,可以把用戶加入 Docker 用戶組(如果你是root用戶的話就不需要了)$ sudo usermod -aG docker $USER
Docker 是服務器----客戶端架構。命令行運行
docker
命令的時候,需要本機有 Docker 服務。如果這項服務沒有啟動,可以用下面的命令啟動,這是Linux下啟動服務方式。# service 命令的用法 $ sudo service docker start # systemctl 命令的用法 $ sudo systemctl start docker
正文
了解Docker
首先學習下Docker
的兩個核心知識點
container
(容器)和image
(鏡像)
Docker
的整個生命周期由三部分組成:鏡像(image
)+容器(container
)+倉庫(repository
)
每台宿主機(電腦),他下載好了Docker
后,可以生成多個鏡像,每個鏡像,可以創建多個容器。發布到倉庫(比如DockerHub)時,以鏡像為單位。可以理解成:一個容器就是一個獨立的虛擬操作系統,互不影響,而鏡像就是這個操作系統的安裝包。想要生成一個容器,就用安裝包(鏡像)生成一次,這就是Docker
的核心概念。
# 列出本機的所有 image 文件。
$ docker image ls
# 刪除 image 文件
$ docker image rm [imageName]
image 文件是通用的,一台機器的 image 文件拷貝到另一台機器,為了方便共享,image 文件制作完成后,可以上傳到網上的倉庫。Docker 的官方倉庫 Docker Hub 是最重要、最常用的 image 倉庫。
image
國內連接 Docker 的官方倉庫很慢,還會斷線,需要將默認倉庫改成國內的鏡像網站
推薦使用官方鏡像 registry.docker-cn.com 。下面是 CentOS 系統的默認倉庫修改方法,其他系統的修改方法參考官方文檔。
打開/etc/default/docker
文件(需要sudo
權限),在文件的底部加上一行,如果沒有該文件可以自己創建。
DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com"
然后,重啟 Docker 服務。
$ sudo service docker restart
現在就會自動從鏡像倉庫下載 image 文件了。
container
image 文件生成的容器實例,本身也是一個文件,稱為容器文件。也就是說,一旦容器生成,就會同時存在兩個文件: image 文件和容器文件。而且關閉容器並不會刪除容器文件,只是容器停止運行而已。
# 列出本機正在運行的容器
$ docker container ls
# 列出本機所有容器,包括終止運行的容器
$ docker container ls --all
上面命令的輸出結果之中,包括容器的 ID。很多地方都需要提供這個 ID,
使用docker container kill
命令可終止容器運行
$ docker container kill [containID]
終止運行的容器文件,依然會占據硬盤空間,可以使用docker container rm
刪除。
$ docker container rm [containerID]
運行上面的命令之后,再使用docker container ls --all
命令,就會發現被刪除的容器文件已經消失了。
Dockerfile 文件
學會使用 image 文件以后,接下來的問題就是,如何可以生成 image 文件?如果你要推廣自己的軟件,勢必要自己制作 image 文件,這就需要用到 Dockerfile 文件。它是一個文本文件,用來配置 image。Docker 根據 該文件生成二進制的 image 文件。
下面通過一個實例,介紹什么是 Dockerfile 文件。
實例
下面我以 這個項目 為例,介紹什么是 Dockerfile 文件,實現讓用戶在 Docker 容器里面運行 Koa 框架。
在你的服務器上克隆該項目(如果沒有Git環境記得安裝)
$ git clone https://github.com/RopeHuo/travis-ci
$ cd travis-ci
.dockerignore文件
.git
node_modules
npm-debug.log
上面代碼表示,這三個路徑要排除,不要打包進入 image 文件。如果你沒有路徑要排除,這個文件可以不要
Dockerfile文件
# 該 image 文件繼承官方的 node image,冒號表示標簽,這里標簽是8.4,即8.4版本的 node。
FROM node:8.4
# 將當前目錄下的所有文件(除了.dockerignore排除的路徑),都拷貝進入 image 文件的/app目錄。
COPY ./ /app
# 指定接下來的工作路徑為/app。
WORKDIR /app
# 在/app目錄下,運行npm install命令安裝依賴。注意,安裝后所有的依賴,都將打包進入 image 文件。
RUN npm install --registry=https://registry.npm.taobao.org
# 將容器 3000 端口暴露出來, 允許外部連接這個端口。
EXPOSE 3000
# 這一行表示等運行image時在shell中自動輸入的命令,不用我們自己再去node文件了。
CMD node hello.js
現在我們服務器上有Dokcer環境,我們通過下面的命令創建image文件
# -t參數用來指定 image 文件的名字,后面還可以用冒號指定標簽。如果不指定,默認的標簽就是latest。
$ docker image build -t travis-ci ./
# 或者
$ docker image build -t travis-ci:0.0.1 ./
如果運行成功,就可以看到新生成的 image 文件travis-ci
了。
$ docker image ls
生成容器
docker container run
命令會從 image 文件生成容器。
# 3000端口是上面Dockerfile文件中暴露的,8000端口是自定義的可以通過外網訪問
# -p參數:容器的 3000 端口映射到本機的 8000 端口
# -it參數:容器的 Shell 映射到當前的 Shell,然后你在本機窗口輸入的命令,就會傳入容器
# travis-ci:0.0.1:image 文件的名字(如果有標簽,還需要提供標簽,默認是 latest 標簽)
# /bin/bash:容器啟動以后,內部第一個執行的命令。這里是啟動 Bash,保證用戶可以使用 Shell
# /bin/bash也屬於CMD命令他會覆蓋我們Dockerfile文件中的CMD命令,兩者只能選一
$ docker container run -p 8000:3000 -it travis-ci /bin/bash
# 或者
$ docker container run -p 8000:3000 -it travis-ci:0.0.1 /bin/bash
如果一切正常,運行上面的命令以后,就會返回一個命令行提示符。
[你的服務器名稱]:/app#
這表示你已經在容器里面了,返回的提示符就是容器內部的 Shell 提示符。執行下面的命令。
node hello.js
這時,Koa 框架已經運行起來了。打開瀏覽器,訪問 [你的域名/ip]:8000,網頁顯示"hello world"
這個例子中,Node 進程運行在 Docker 容器的虛擬環境里面,進程接觸到的文件系統和網絡接口都是虛擬的,與本機的文件系統和網絡接口是隔離的,因此需要定義容器與物理機的端口映射(map)。
現在,在容器的命令行,按下 Ctrl + c 停止 Node 進程,然后按下 Ctrl + d (或者輸入 exit)退出容器。此外,也可以用docker container kill
終止容器運行。
# 列出所有容器,不加 -a 僅列出正在運行的,像退出了的或者僅僅只是創建了的就不列出來
$ docker ps -a
# 在本機的另一個終端窗口,列出當前運行的容器,查出容器的 ID
$ docker container ls
# 停止指定的容器運行
$ docker container kill [containerID]
容器停止運行之后,並不會消失,用下面的命令刪除容器文件。
# 查出容器的 ID
$ docker container ls --all
# 刪除指定的容器文件
$ docker container rm [containerID]
CMD 命令
容器啟動以后,需要手動輸入命令node hello.js
。我們可以把這個命令寫在 Dockerfile 里面,這樣容器啟動以后,這個命令就已經執行了,不用再手動輸入了。
FROM node:8.4
COPY ./ /app
WORKDIR /app
# RUN
RUN npm install --registry=https://registry.npm.taobao.org
EXPOSE 3000
# CMD
CMD node hello.js
上面有RUN命令和CMD命令,RUN
命令與CMD
命令的區別在哪里?簡單說,RUN
命令在 image 文件的構建階段執行,執行結果都會打包進入 image 文件;CMD
命令則是在容器啟動后執行。另外,一個 Dockerfile 可以包含多個RUN
命令,但是只能有一個CMD
命令。
注意,指定了CMD
命令以后,docker container run
命令就不能附加命令了(比如前面的/bin/bash
),否則它會覆蓋Dockerfile中的CMD
命令。現在,啟動容器可以使用下面的命令。
# 這里多了一個--rm,意思是在容器終止運行后自動刪除容器文件。
$ docker container run --rm -p 8000:3000 -it travis-ci:0.0.1
發布image
手動發布
首先,去 hub.docker.com 或 cloud.docker.com 注冊一個賬戶。然后,用下面的命令登錄。
$ docker login
接着,為本地的 image 標注用戶名和版本。
$ docker image tag [image名稱] [你的用戶名]/[倉庫名]:[標簽]
# 例子
$ docker image tag travis-ci:0.0.1 rope/travis-ci:0.0.1
也可以不標注用戶名,重新構建一下 image 文件即可。
# 記得進入項目目錄后再操作
$ docker image build -t [username]/[repository]:[tag] ./
最后,發布 image 文件。
$ docker image push [username]/[repository]:[tag]
發布成功以后,登錄 hub.docker.com,就可以看到已經發布的 image 文件。
自動發布
我們使用gitHub+travis+docker
來形成一套完整的自動化流水線
只要我們push新的代碼到gitHub上,自動幫我們構建出新的代碼發布到DockerHub,然后我們拉取新的鏡像即可
首先我們先進入 Travis CI 官網配置,注冊綁定自己的gitHub賬號,然后在左側將自己需要git push
后自動構建鏡像的倉庫加入可參考這篇文章
我們繼續使用上面用到的travis-ci項目,為了驗證我們下面的操作是成功的可以將項目中的hello.js顯示的hello world改成其他內容。
查看 .travis.yml 文件
language: node_js
node_js:
- '12'
services:
- docker
before_install:
- npm install
script:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker build -t mufengsm/travis-ci:latest .
- docker push mufengsm/travis-ci:latest
注意 :mufengsm/travis-ci
應該換成你的用戶名/包名,再push
代碼
每次push
代碼到GitHub,Travis-CI都會下載,然后根據package.json
文件下載所需包,再登陸DockerHub賬戶,再打包並發布到DockerHub,這樣你下載的鏡像就是有最新的代碼。
打開travis-ci中所監聽GitHub項目的設置頁面,然后添加兩個環境變量,這個用戶名和密碼和你的DockerHub賬戶是對應的:
DOCKER_USERNAME和DOCKER_PASSWORD
特別提示:這里的Docker
容器,想要后台運行,就必須有一個前台進程。容器運行的命令如果不是那些一直掛起的命令(比如tcp,ping,node
),就是會自動退出的,通過 docker ps -a
可以看到容器關閉的原因
當配置成功,代碼被推送到GitHub
上后,travis-ci
幫我們自動構建發布新鏡像
一定要學會使用: docker ps -a
查看容器的狀態
至此,發布,自動構建鏡像已經完成
拉取新的鏡像
正式開始拉取鏡像,啟動容器
我們剛才發布的鏡像名稱是:mufengsm/travis-ci
清除鏡像和容器
如果在此之前你創建了很多鏡像和容器,一個個刪除又太麻煩,下面的命令可以幫到你。
# docker中 啟動所有的容器命令
docker start $(docker ps -a | awk '{ print $1}' | tail -n +2)
#docker中 關閉所有的容器命令
docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)
#docker中 刪除所有的容器命令
docker rm $(docker ps -a | awk '{ print $1}' | tail -n +2)
#docker中 刪除所有的鏡像
docker rmi $(docker images | awk '{print $3}' |tail -n +2)
#tail -n +2 表示從第二行開始讀取
然后使用:
$ docker image pull mufengsm/travis-ci:latest
拉取鏡像,這時候需要下載,拉取完成后,使用docker images
可以看到mufengsm/travis-ci:latest
鏡像已經存在了
我們使用
# --rm參數,在容器終止運行后自動刪除容器文件。
$ docker container run --rm -p 8000:3000 -it mufengsm/travis-ci:latest
創建這個鏡像的容器,並且綁定在端口號8000
上
瀏覽器輸入 [你的域名/ip]:8000
發現,訪問成功。
最后
我們再梳理下整個流程,創建項目,創建Dockerfile文件,創建travis.yml文件,發布到GitHub,Travis-CI監聽項目,自動打包發布到DockerHub,拉取新的鏡像,再運行。
參考文章