部署基於Gitlab+Docker+Rancher+Harbor的前端項目這一篇就夠了
就目前的形勢看,一家公司的運維體系不承載在 Docker+Harbor(或 Pouch 等同類平台)之上都不好意思說自己的互聯網公司。當然這些技術也不適用於全部公司,技術在迭代,平台也一樣,把我使用的工具和大家分享下,一起成長(文章中擴展可按需Google)。
Docker
docker的架構圖如下:
從圖中可以看出幾個組成部分
docker client: 即docker命令行工具docker host: 宿主機,docker daemon的運行環境服務器docker daemon:docker的守護進程,docker client通過命令行與docker daemon交互container: 最小型的一個操作系統環境,可以對各種服務以及應用容器化image: 鏡像,可以理解為一個容器的模板配置,通過一個鏡像可以啟動多個容器registry: 鏡像倉庫,存儲大量鏡像,可以從鏡像倉庫拉取和推送鏡像
我在剛接觸到Docker的時候,產生了一種錯覺--這不就是個性能不錯的虛擬機嗎?顯然他能做的遠比虛擬機多得多。具體表現在 Docker 不是在宿主機上虛擬出一套硬件后再虛擬出一個操作系統,而是讓 Docker 容器里面的進程直接運行在宿主機上(Docker 會做文件、網絡等的隔離),這樣一來 Docker 會 “體積更輕、跑的更快、同宿主機下可創建的個數更多”(類似於一個一個的沙箱,互相不暴露接口,互相不影響)。
Docker 中有三個核心概念:Image、Container、Repository。
- Image: 和 windows 的那種 iso 鏡像相比,Docker 中的鏡像是分層的,可復用的,而非簡單的一堆文件迭在一起(類似於一個壓縮包的源碼和一個 git 倉庫的區別)。
- Container: 容器的存在離不開鏡像的支持,他是鏡像運行時的一個載體(類似於實例和類的關系)。依托 Docker 的虛擬化技術,給容器創建了獨立的端口、進程、文件等“空間”,Container 就是一個與宿機隔離 “沙箱”。沙箱可在宿主機之間可以進行 port、volumes、network 等的通信。
- Repository: Docker 的倉庫和 git 的倉庫比較相似,擁有倉庫名、tag。在本地構建完鏡像之后,即可通過倉庫進行鏡像的分發。常用的 Docker hub 有 https://hub.docker.com/ 、 https://cr.console.aliyun.com/ 等。
底層原理
docker 底層使用了一些 linux 內核的特性,大概有 namespace,cgroups 和 ufs
namespace
docker 使用 linux namespace 構建隔離的環境,它由以下 namespace 組成
pid: 隔離進程net: 隔離網絡ipc: 隔離 IPCmnt: 隔離文件系統掛載uts: 隔離hostnameuser: 隔離uid/gid
control groups
也叫 cgroups,限制資源配額,比如某個容器只能使用 100M 內存
Union file systems
UnionFS 是一種分層、輕量級並且高性能的文件系統,支持對文件系統的修改作為一次提交來一層層的疊加。docker 的鏡像與容器就是分層存儲,可用的存儲引擎有 aufs,overlay 等。
鏡像
鏡像是一份用來創造容器的配置文件,而容器可以視作最小型的一個操作系統(類似於容器由鏡像解壓而來)。
docker 的鏡像和容器都使用了 unionFS 做分層存儲,鏡像作為只讀層是共享的,而容器在鏡像之上附加了一層可寫層,最大程度地減少了空間的浪費,詳見下圖
鏡像倉庫與拉取
我們可以在官方鏡像倉庫拉取鏡像,也可以自己構造鏡像
# 加入拉取一個 node:alpine 的鏡像
$ docker pull node:alpine
# 查看鏡像信息
$ docker inspect node:alpine
# 列出所有鏡像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node alpine f20a6d8b6721 13 days ago 105MB
mongo latest 965553e202a4 2 weeks ago 363MB
centos latest 9f38484d220f 8 months ago
鏡像的構造與發布
鏡像倉庫里找不到全部的鏡像,這時我們需要為自己的業務去構建鏡像了。
-t 指定標簽
# -t node-base:10: 鏡像以及版本號
# .: 指當前路徑
$ docker build -t node-base:10 ./
#使用docker push將鏡像推送到鏡像倉庫
$ docker push node-base:10
Dockerfile
在使用docker部署自己應用時,往往需要自己構建鏡像。docker使用Dockerfile作為配置文件構建鏡像,簡單看一個node應用構建的dockerfile
FROM node:alpine
ADD package.json package-lock.json /code/
WORKDIR /code
RUN npm install --production
#.為當前文件目錄 /code為鏡像內的目錄
ADD . /code
CMD npm start
FROM
基於一個舊的鏡像,格式如下
FROM <image> [AS <name>]
# 在多階段構建時會用到
FROM <image>[:<tag>] [AS <name>]
ADD
把目錄,或者 url 地址文件加入到鏡像的文件系統中
ADD [--chown=<user>:<group>] <src>... <dest>
RUN
執行命令,由於 ufs 的文件系統,它會在當前鏡像的頂層新增一層
RUN <command>
CMD
指定容器如何啟動
一個 Dockerfile 中只允許有一個 CMD
# exec form, this is the preferred form
CMD ["executable","param1","param2"]
# as default parameters to ENTRYPOINT
CMD ["param1","param2"]
# shell form
CMD command param1 param2
容器
鏡像與容器的關系,類似於代碼與進程的關系。
docker run創建容器docker stop停止容器docker rm刪除容器
創建容器
基於 nginx 鏡像創建一個最簡單的容器:啟動一個最簡單的 http 服務
使用 docker run 來啟動容器,docker ps 查看容器啟動狀態
$ docker run -d --name nginx -p 8888:80 nginx:alpine
$ docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
404e88f0d90c nginx:alpine "nginx -g 'daemon of…" 4 minutes ago Up 4 minutes 0.0.0.0:8888->80/tcp nginx
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
其中:
-d: 啟動一個daemon進程--name: 為容器指定名稱-p host-port:container-port: 宿主機與容器端口映射,方便容器對外提供服務nginx:alpine: 基於該鏡像創建容器
此時在宿主機使用 curl 測試容器提供的服務是否正常
curl localhost:8888
會在下方打印出html代碼
使用docker exec -it container-name命令可以進入容器的環境中
容器管理
docker ps 列出所有容器
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
404e88f0d90c nginx:alpine "nginx -g 'daemon of…" 4 minutes ago Up 4 minutes 0.0.0.0:8888->80/tcp nginx
498e7d74fb4f nginx:alpine "nginx -g 'daemon of…" 7 minutes ago Up 7 minutes 80/tcp lucid_mirzakhani 2ce
10556dc8f redis:4.0.6-alpine "docker-entrypoint.s…" 2 months ago Up 2 months 0.0.0.0:6379->6379/tcp apolloserverstarter_redis_1
docker port 查看容器端口映射
$ docker port nginx 80/tcp -> 0.0.0.0:8888
docker stats 查看容器資源占用
$ docker stats nginx CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
404e88f0d90c nginx 0.00% 1.395MiB / 1.796GiB 0.08% 632B / 1.27kB 0B / 0B 2
Harbor
它的目標是幫助用戶迅速搭建一個企業級的 Docker registry 服務。它以 Docker 公司開源的 registry 為基礎,提供了管理UI,基於角色的訪問控制(Role Based Access Control),AD/LDAP集成、以及審計日志(Auditlogging) 等企業用戶需求的功能,同時還原生支持中文。Harbor 的每個組件都是以 Docker 容器的形式構建的,使用 Docker Compose 來對它進行部署。
Rancher
rancher 容器管理平台 在生產環境中輕松快捷的部署和管理容器 管理K8s 內置CI/CD 快速搭建 導入和納管 集中式身份。
准確的說,Rancher是一套容器管理打包方案,支持三種編排引擎:Kubernetes,Swarm,還有Rancher自己開發的Cattle(最近好像換成了Mesos)。從功能的完整性和易用性來看,Rancher甚至可以算得上一個商業軟件了,部署極其簡單,這也是我們選擇它作為入門級容器管理平台的原因。以下是Rancher的組件圖:
雖然Rancher非常的易用,但是rancher也不都是優點,隨着后端機器和項目數量的增加,它的一些問題也更易暴露,UI卡頓,發布速度越來越慢,1.3之后甚至經常出現服務的預期狀態(容器數量,版本)無法被保證,卡在發布中或者完成中狀態。團隊后續可能會考慮使用kubernetes。
基於GitLab的CI/CD
個人理解就是把代碼測試、打包、發布等工作交給一些工具來自動完成。這樣可以提高效率,減少失誤,開發人員只需要關心開發和提交代碼到git就可以了。
使用工具如gitlab-CI,這種方式的原理就是為項目在自己的服務器安裝上注冊gitlab-runner,注冊會有一個token,服務器上運行gitlab-runner后,runner會輪詢的發送帶token的http請求給gitlab,如果gitlab有任務了,(一般是git push),那么會把任務信息返回給runner,然后runner就開始調用注冊時選的Executor(我是用的shell)來執行項目根目錄下的配置文件.gitlab-ci.yml,執行后把結果反饋給gitlab。
詳細的工作原理請參考:
對GitLab-CI,GitLab-Runner等概念不清楚,參考:
GitLab-CI與GitLab-Runner - CNundefined - 博客園開發環境要求
1、gitlab遠程倉庫
2、本地配置文件gitLab-ci.yml
stages:
- test
- build
- push
- deploy
variables:
image:.......
.deploy_test_refs: &deploy_test_refs
- development
- test
.deploy_production_refs: &deploy_production_refs
- master
# all_deploy_refs = deploy_test_refs + deploy_production_refs, but YAML cannot concat arrays
.all_deploy_refs: &all_deploy_refs
- development
- test
- master
3、服務器上配置nginx、gitlab-runner(注冊runner,修改runner的權限)
sudo chown -R gitlab-runner:gitlab-runner /home/gitlab-runner
sudo chmod -R 777 /home/gitlab-runner
開啟runner
gitlab-runner run
4、本地配置好node、git
配置成功展示界面:
參考文章:
前端項目基於GitLab-CI的持續集成/持續部署(CI/CD) - 掘金使用Docker+Rancher(結合gitlab)+Harbor的具體流程
環境准備
1、macpro+多出來的服務器(沒有也可以)
2、docker 版本:18 (最新也成)
3、docker-compose:1.24 (最新也成)
4、Harbor:1.1.2(最新也行)
安裝docker
brew cask install docker
打開docker客戶端之后再item中輸入
docker login 域名
然后就可以在客戶端中輸入用戶名與密碼,由於作者使用公司的內網(不涉及業務內容),因此需要事先配置好推到harbor內的權限
處理過權限問題,之后的階段就可以進入相應的文件夾進行手動的配置,前提是要先寫好一個類似於build.sh的文件,內部配置好各種命令,build文件中的內容
function build() {
echo "------------------------------ BUILD ------------------------------"
(cd frontend && env COMMIT_ID=${COMMIT_ID} BUILD_TIME=${TIMESTAMP2} $(cat .env.${DEPLOY}) yarn build)
rm -rf docker/frontend
cp -r frontend/build docker/frontend
# local IMAGES=`docker images -q -f 'dangling=true'`
# [ "$IMAGES" != '' ] && docker rmi -f ${IMAGES}
# local IMAGES=`docker images -q -f "label=app=${APP}"`
# [ "$IMAGES" != '' ] && docker rmi -f ${IMAGES}
docker build -t ${TAG} ${DOCKER_DIR}
}
function push() {
echo "------------------------------ PUSH ------------------------------"
docker push ${TAG}
export SERVICE_NAME NAMESPACE IMAGE_URL
envsubst <deploy/${APP}.tmpl || :
}
function all() {
build
push
}
function usage() {
echo "Usage: $0 [build|push|all] [production|test]"
}
function main() {
case ${CMD} in
b*) build ;;
p*) push ;;
a*) all ;;
*) usage ;;
esac
}
init $@
main
配置好后且確保權限無誤即可執行:
./build.sh all test
配置執行后會直接push鏡像到harbor內(事先配置好)。
查看docker中的各種內容的命令:
docker ps
See 'docker --help'
MacBook-Pro:111$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
查看已經打出的鏡像
docker images
MacBook-Pro:111$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.momenta.works/cla/milky-web 191202-test 1532be927f8d 5 hours ago 18.7MB
registry.momenta.works/cla/milky-web 191128-test 1af4615c4cb3 4 days ago 18.7MB
registry.momenta.works/cla/milky-web 191121-test f6cb17d8b0a0 11 days ago 18.7MB
registry.momenta.works/cla/milky-web 191120-production 3e11cd30dd89 11 days ago 18.7MB
registry.momenta.works/cla/milky-web 191120-test ee0909ecd9f7 11 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 13993e12200a 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 8de9f053335a 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 7828f22eb355 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> c23b51230cad 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> f5169dc0f863 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> eb5463875800 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 618d7f09c2f6 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> b682475e4d9b 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 85420f94ff4c 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 972cc2cc9c7c 12 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 08098283428a 12 days ago 18.7MB
registry.momenta.works/cla/milky-web 191119-test bdc5d28d724f 12 days ago 18.7MB
registry.momenta.works/cla/milky-web 191118-test 3aca38625579 13 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> 5b4dcdc14def 13 days ago 18.7MB
registry.momenta.works/cla/milky-web <none> f40db7e196fb 2 weeks ago 18.7MB
registry.momenta.works/cla/milky-web <none> ff2c5da90a90 2 weeks ago 18.7MB
registry.momenta.works/cla/milky-web 191116-test c2e20e00fa04 2 weeks ago 18.7MB
registry.momenta.works/cla/milky-web 191115-test 2d0ebce7a82c 2 weeks ago 18.7MB
nginx 1.15-alpine dd025cdfe837 6 months ago 16.1MB
將打好的鏡像上傳到相對應的harbor倉庫中:
docker push registry.momenta.works/cla/milky-web:-test
在rancher中對相應的服務(微服務)edit相應的鏡像地址即可
以上是權限沒有配置好情況下的操作
假如說我們的權限配置沒有問題了,直接執行build.sh即可(省略中間步驟),最后在rancher中edit相應的鏡像即可
未完待續(harbor與rancher的使用及配置會在近期附上)
Happy Hacking

