部署基于Gitlab+Docker+Rancher+Harbor的前端项目这一篇就够了
部署基于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