全文采用的是阿里雲的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 infoDocker 需要用戶具有 sudo 權限,為了避免每次命令都輸入
sudo,可以把用戶加入 Docker 用戶組(如果你是root用戶的話就不需要了)$ sudo usermod -aG docker $USERDocker 是服務器----客戶端架構。命令行運行
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,拉取新的鏡像,再運行。
參考文章
