传统方案
基于docker
随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件
开发的质量已经慢慢成为开发过程中不可回避的问题。互联网软件的开发和发布,已经形成了一套标准流程。
如: 在互联网企业中,每时每刻都有需求的变更,bug的修复, 为了将改动及时更新到生产服务器上,下面的图片我们需要每天执行N多次,开发人员完整代码自测后提交到git,然后需要将git中最新的代码生成镜像并部署到测试服务器,如果测试通过了还需要将最新代码部署到生产服务器。如果采用手动方式操作,那将会浪费大量的时间浪费在运维部署方面。
现在的互联网企业,基本都会采用以下方案解决:
持续集成(Continuous integration,简称 CI)。
持续部署(continuous deployment, 简称 CD)
持续集成 (Continuous integration,简称 CI) 指的是,频繁地(一天多次)将代码集成到主干。
它的好处主要有两个。
1、快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。
2、防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
Martin Fowler 说过,”持续集成并不能消除 Bug,而是让它们非常容易发现和改正。”
与持续集成相关的,还有两个概念,分别是持续交付和持续部署。
持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。
持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。
持续部署的前提是能自动化完成测试、构建、部署等步骤。
为了保证团队开发人员提交代码的质量,减轻了软件发布时的压力;
持续集成中的任何一个环节都是自动完成的,无需太多的人工干预,有利于减少重复
过程以节省时间、费用和工作量;接下来我们会演示一套基本的自动化持续集成和持续部署方案,来帮助大家理解互联网企业的软件部署方案。
计划如下:
1. 开发人员将代码提交到 git 指定分支 如: dev
2. git仓库触发push事件,发送webhooks通知到持续集成软件
3. 持续集成软件触发构建任务,对dev分支的代码进行构建、编译、单元测试
4. 如果构建失败,发送邮件提醒代码提交人员或管理员
5. 如果构建成功,最新代码将会被构建Docker镜像并上传到注册中心
6. 构建成功触发webhooks通知容器编排软件,进行服务升级
7. 容器编排软件,触发对应的服务升级任务, 将创建对应服务的新容器替换之前的容器
8. 完成最新代码的自动构建与自动部署,全程无工作人员干预
购买地址: 阿里云ECS
1 选择配置
2 选择服务和对应的操作系统
3 选择网络带宽 5M
默认5m即可,当然想更快可以设置大一些,但流量是单独收费的
4 直接点击确认订单
5 点击创建实例
点击管理控制台进入服务器管理界面如下:
其中:
公网IP: 47.103.2.34.130
私网IP: 172.20.170.76
收到短信: 发送服务器的 密码
重置密码:
接收短信后,立即重启生效.
推荐使用 finalshell 连接.
1 打开 finalshell 创建 ssh 连接
2 输入 阿里云的 用户名(root) 和 设置的新密码
在云服务器中,只有配置了安全规则的端口才允许被外界访问
一般默认 开启: 80 (http) 443 (https) 22 (ssh远程连接) 3389 (windows远程连接)
那如果你安装了mysql 端口是3306 ,那么外界是无法直接访问到的,需要配置一下规则
在入方向中配置安全规则: ( 用户 访问 --> 阿里云)
如果配置端口范围: 3306/3306 那就是允许3306端口访问
但是我们的软件很多, 可以通过 1/65535
范围 来开放所有的端口访问**(不安全,学习阶段这么搞)**
(1)yum 包更新到最新
sudo yum update -y
(2)安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
(3)设置yum源为阿里云
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
(4)安装docker
sudo yum -y install docker-ce
(5)安装后查看docker版本
docker -v
(6)启动docker
systemctl start docker
#设置开机自启
systemctl enable docker
(7)阿里云镜像加速
阿里云开设了一个容器开发平台
需要注册一个属于自己的阿里云账户,登录后进入管理中心
针对Docker客户端版本大于 3.2.10.0 的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://hf23ud62.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
观察镜像是否生效:
docker info
开启docker远程访问功能:
vi /lib/systemd/system/docker.service
替换ExecStart 一行配置:
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
# 重启docker
systemctl daemon-reload
systemctl restart docker
全部上传到阿里云的**/root目录**
通过命令安装:
# * 如果下载慢,可以上传资料中的 docker-compose 文件到 /usr/local/bin/
cp /root/docker-compose /usr/local/bin/
# 修改权限
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
实战练习相关软件 一键脚本
在root
目录 创建 docker-compose.yml
脚本文件 拷贝下面内容
# 通过docker命令即可启动所有软件
version: '3'
services:
mysql:
image: mysql:5.7
ports:
- "3306:3306"
volumes:
- "/root/mysql/conf:/etc/mysql/conf.d"
- "/root/mysql/logs:/logs"
- "/root/mysql/data:/var/lib/mysql"
- "/root/mysql/init:/docker-entrypoint-initdb.d/"
environment:
- MYSQL_ROOT_PASSWORD=root
restart: always
nacos:
image: nacos/nacos-server:1.3.2
ports:
- "8848:8848"
restart: always
environment:
- MODE=standalone
- JVM_XMS=512m
- JVM_XMX=512m
- JVM_XMN=256m
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=mysql
- MYSQL_SERVICE_PORT=3306
- MYSQL_SERVICE_USER=root
- MYSQL_SERVICE_PASSWORD=root
- MYSQL_SERVICE_DB_NAME=nacos_config
- NACOS_SERVER_IP=101.132.251.26
depends_on:
- mysql
xxljob:
image: xuxueli/xxl-job-admin:2.2.0
volumes:
- "/tmp:/data/applogs"
environment:
PARAMS: "--spring.datasource.url=jdbc:mysql://101.132.251.26:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai --spring.datasource.username=root --spring.datasource.password=root"
ports:
- "8888:8080"
depends_on:
- mysql
restart: always
redis:
image: redis:6.2.5
ports:
- "6379:6379"
restart: always
command: redis-server --appendonly yes --requirepass root
elasticsearch:
image: elasticsearch:7.12.1
ports:
- "9200:9200"
- "9300:9300"
environment:
- "discovery.type=single-node"
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
volumes:
- "/root/elasticsearch:/usr/share/elasticsearch/plugins"
restart: always
kibana:
image: kibana:7.12.1
links:
- elasticsearch
environment:
- "ELASTICSEARCH_URL=http://elasticsearch:9200"
ports:
- "5601:5601"
depends_on:
- elasticsearch
restart: always
mq:
image: rabbitmq:3.8-management
restart: always
ports:
- 5672:5672
- 15672:15672
volumes:
- "mq-config:/plugins"
environment:
- "RABBITMQ_DEFAULT_USER=itcast"
- "RABBITMQ_DEFAULT_PASS=123321"
volumes:
mq-config:
使用步骤
运行所有容器:
# 运行
docker-compose up -d
# 停止
docker-compose stop
# 停止并删除容器
docker-compose down
# 查看日志
docker-compose logs -f [service...]
# 查看命令
docker-compose --help
创建es索引库
PUT /item
{
"settings": {
"analysis": {
"analyzer": {
"text_anlyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
},
"completion_analyzer": {
"tokenizer": "keyword",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"id":{
"type": "keyword"
},
"name":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart",
"copy_to": "all"
},
"image":{
"type": "keyword",
"index": false
},
"price":{
"type": "long"
},
"brand":{
"type": "keyword",
"copy_to": "all"
},
"category":{
"type": "keyword",
"copy_to": "all"
},
"sold":{
"type": "integer"
},
"commentCount":{
"type": "integer"
},
"isAd":{
"type": "boolean"
},
"all":{
"type": "text",
"analyzer": "text_anlyzer",
"search_analyzer": "ik_smart"
},
"suggestion":{
"type": "completion",
"analyzer": "completion_analyzer"
}
}
}
}
rabbitmq安装延迟队列 (暂不需要)
# 将mq的延迟插件拷贝至挂在目录
cp /root/rabbitmq_delayed_message_exchange-3.8.9-0199d11c.ez /var/lib/docker/volumes/root_mq-config/_data
# 进入rabbitmq容器
docker exec -it root_mq_1 bash
# 开启插件
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
执行docker命令安装:
docker run --name jenkins -u root -d -p 8080:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock jenkinsci/blueocean
管理后台初始化设置
http://服务器IP:8080/
第一次访问需要管理员密码:
docker exec -it jenkins bash
cat /var/jenkins_home/secrets/initialAdminPassword
解锁后 选择安装推荐的插件
这一步等待时间较长, 安装完成之后, 创建管理员用户:
安装 maven集成插件
安装git插件
在实现持续集成之前, 需要确保以下插件安装成功。
Maven Integration plugin
: Maven 集成管理插件。(必装)Git
: Git 集成插件。(必装)Gitee
: Git 集成插件。(选装)安装方法:
注意,如果上面安装正常,无需配置 如果没有安装按钮,或者安装失败 需要更改配置
在安装插件的高级配置中,修改升级站点的连接为:http://updates.jenkins.io/update-center.json 保存
安装完毕后重启jenkins
systemctl restart jenkins
配置maven环境
上传maven 至 /var/jenkins_home 目录:
cp /root/apache-maven-3.3.9.zip /var/jenkins_home
# 下载unzip命令
yum install -y unzip
# 将压缩包上传至 /usr/local/maven下 解压
unzip -o /var/jenkins_home/apache-maven-3.3.9.zip
进入【系统管理】–> 【全局工具配置】
点击新增maven 配置name: maven 配置maven地址: /var/jenkins_home/apache-maven-3.3.9
每个微服务使用的dockerfile的方式进行构建镜像后创建容器,需要在每个微服务中添加docker相关的配置
(1)修改需要部署微服务的pom文件,添加部署配置
<build>
<finalName>appfinalName>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
<plugin>
<groupId>com.spotifygroupId>
<artifactId>docker-maven-pluginartifactId>
<version>1.2.2version>
<configuration>
<imageName>139.196.153.42:5000/${project.artifactId}:${project.version}imageName>
<baseImage>java:8-alpinebaseImage>
<entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]entryPoint>
<resources>
<resource>
<targetPath>/targetPath>
<directory>${project.build.directory}directory>
<include>${project.build.finalName}.jarinclude>
resource>
resources>
<dockerHost>http://139.196.153.42:2375dockerHost>
configuration>
plugin>
plugins>
build>
构建基础依赖打包任务 hmall-cloud
点击【构建触发器】–【构建】–【增加构建步骤】–【调用顶层Maven目标】–【填写配置】–【保存】
clean install -Dmaven.test.skip=true
依次构建其它微服务 重点设置:
(1)build设置: clean package -DskipTests docker:build
(2)build执行Shell脚本:
docker rm -f item || true
docker run -id --name item -p 8081:8081 139.196.153.42:5000/hmall-service-item:1.0-SNAPSHOT || true
docker rmi $(docker images | grep "none" | awk '{print $3}') || true
删除item容器 || true
如果报错继续向下执行命令
创建item容器
删除旧的镜像
前端:
修改前端资源 并 上传到服务器:
修改hm-mall-admin 下 index.html页面中网关的路径 改为服务器路径
修改hm-mall-portal / js 下 common.js中网关的路径 改为服务器路径
# 创建nginx容器
docker run -id --name nginx -p 80:80 -p 9001:9001 -p 9002:9002 nginx
# 将前端资源拷贝到nginx中
docker cp hm-mall-admin nginx:/
docker cp hm-mall-portal nginx:/
docker cp nginx.conf nginx:/etc/nginx/
# 重启nginx
docker restart nginx
(1) 此功能需要下载gitee插件
(2) 有插件后 在构建触发器中勾选Gitee webhook触发构建
(3)生成构建触发密码
(4)打开Gitee仓库,设置webhooks钩子
(5)将jenkins中的触发路径 和 触发密码 写入到表单
(6)点击测试 查看jenkins任务是否触发,如果触发代表成功