软件开发最开始是由两个团队组成:
这看似两个目标不同的团队需要协同完成一个软件的开发。
在开发团队指定好计划并完成coding后,需要提供到运维团队。
运维团队向开发团队反馈需要修复的BUG以及一些需要返工的任务。
这时开发团队需要经常等待运维团队的反馈。这无疑延长了事件并推迟了整个软件开发的周期。
会有一种方式,在开发团队等待的时候,让开发团队转移到下一个项目中。等待运维团队为之前的代码提供反馈。
可是这样就意味着一个完整的项目需要一个更长的周期才可以开发出最终代码。
基于现在的互联网现状,更推崇敏捷式开发,这样就导致项目的迭代速度更快,但是由于开发团队与运维团队的沟通问题,会导致新版本上线的时间成本很高。这又违背的敏捷式开发的最初的目的。
那么如果让开发团队和运维团队整合到成一个团队,协同应对一套软件呢?这就被称为DevOps。
DevOps,字面意思是Development &Operations的缩写,也就是开发&运维。
虽然字面意思只涉及到了开发团队和运维团队,其实QA测试团队也是参与其中的。
网上可以查看到DevOps的符号类似于一个无穷大的符号
DevOps的方式可以让公司能够更快地应对更新和市场发展变化,开发可以快速交付,部署也更加稳定。
核心就在于简化Dev和Ops团队之间的流程,使整体软件开发过程更快速。
整体的软件开发流程包括:
PLAN
:开发团队根据客户的目标制定开发计划CODE
:根据PLAN开始编码过程,需要将不同版本的代码存储在一个库中。BUILD
:编码完成后,需要将代码构建并且运行。TEST
:成功构建项目后,需要测试代码是否存在BUG或错误。DEPLOY
:代码经过手动测试和自动化测试后,认定代码已经准备好部署并且交给运维团队。OPERATE
:运维团队将代码部署到生产环境中。MONITOR
:项目部署上线后,需要持续的监控产品。INTEGRATE
:然后将监控阶段收到的反馈发送回PLAN阶段,整体反复的流程就是DevOps的核心,即持续集成、持续部署。为了保证整体流程可以高效的完成,各个阶段都有比较常见的工具,如下图:
最终可以给DevOps下一个定义:DevOps 强调的是高效组织团队之间如何通过自动化的工具协作和沟通来完成软件的生命周期管理,从而更快、更频繁地交付更稳定的软件。
自动化的工具协作和沟通来完成软件的生命周期管理
基础环境信息:
在code阶段,我们需要将不同版本的代码存储到一个仓库中,常见的版本控制工具就是SVN或者Git,这里我们采用Git作为版本控制工具,GitLab作为远程仓库。
单独准备服务器,采用Docker安装
查看GitLab镜像
docker search gitlab
拉取GitLab镜像
docker pull gitlab/gitlab-ce
准备docker-compose.yml文件
version: '3.1'
services:
gitlab:
image: 'gitlab/gitlab-ce:latest'
container_name: gitlab
restart: always
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://192.168.1.190:8929'
gitlab_rails['gitlab_shell_ssh_port'] = 2224
ports:
- '8929:8929'
- '2224:2224'
volumes:
- './config:/etc/gitlab'
- './logs:/var/log/gitlab'
- './data:/var/opt/gitlab'
启动容器
docker-compose up -d
访问GitLab首页
查看root用户初始密码
docker exec -it gitlab cat /etc/gitlab/initial_root_password
登录root用户
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具
Jenkins应用广泛,大多数互联网公司都采用Jenkins配合GitLab、Docker、K8s作为实现DevOps的核心工具。
Jenkins最强大的就在于插件,Jenkins官方提供了大量的插件库,来自动化CI/CD过程中的各种琐碎功能。
Jenkins最主要的工作就是将GitLab上可以构建的工程代码拉取并且进行构建,再根据流程可以选择发布到测试环境或是生产环境。
一般是GitLab上的代码经过大量的测试后,确定发行版本,再发布到生产环境。
CI/CD可以理解为:
docker-compose.yml
注意挂载数据卷,且data目录赋予足够的权限
version: "3.1"
services:
jenkins:
image: jenkins/jenkins:2.401.1-lts
container_name: jenkins
ports:
- 8080:8080
- 50000:50000
volumes:
- ./data/:/var/jenkins_home/
启动Jenkins容器后,由于Jenkins需要下载大量内容,可以设置国内镜像站提高下载速度。
<sites>
<site>
<id>defaultid>
<url>https://updates.jenkins.io/update-center.jsonurl>
site>
sites>
<sites>
<site>
<id>defaultid>
<url>http://mirror.esuni.jp/jenkins/updates/update-center.jsonurl>
site>
sites>
代码拉取到Jenkins本地后,需要在Jenkins中对代码进行构建,这里需要Maven的环境,而Maven需要Java的环境,接下来需要在Jenkins中安装JDK和Maven,并且配置到Jenkins服务。
构建Java项目的工具一般有两种选择,一个是Maven,一个是Gradle。
这里我们选择Maven作为项目的编译工具。
jenkins/jenkins:2.401.1-lts
镜像集成了Java11,所以jdk目录放入存储卷后并未使用,特此说明。)注意修改Maven的仓库地址,以免后期打包依赖下载不了。
程序包构建好之后,就可以根据情况发布环境,配置之前下载好的插件Publish Over SSH。
项目准备dockerfile等并推送gitlab
FROM java:openjdk-8u111
COPY *.jar /usr/local/test.jar
WORKDIR /usr/local/
ENTRYPOINT ["/bin/sh","-c","java -Dfile.encoding=utf8 -Djava.security.egd=file:/dev/./urandom -jar test.jar"]
version: "3"
services:
my_test:
build:
context: ./
dockerfile: dockerfile
image: test:v1
container_name: my_test
ports:
- "9090:9090"
cd /usr/local/test/docekr
mv ../target/*.jar ./
docker-compose down
docker-compose up -d --build
Jenkins尝试构建并发布
程序代码在经过多次集成操作到达最终可以交付,持续交付整体流程和持续集成类似,不过需要选取指定的发行版本。
搭建的地方有两个坑,集中在配置maven和jdk两个地方,在这里列举一下,免得走弯路。
Cannot run program "var/jenkins_home/maven/bin/mvn" (in directory "/var/jenkins_home/workspace/mytest"): error=2, No such file or directory
的错误。解决方案如下:设置之后配置正常。
Sonar Qube是一个开源的代码分析平台,支持Java、Python、PHP、JavaScript、CSS等25种以上的语言,可以检测出重复代码、代码漏洞、代码规范和安全性漏洞的问题。
Sonar Qube可以与多种软件整合进行代码扫描,比如Maven,Gradle,Git,Jenkins等,并且会将代码检测结果推送回Sonar Qube并且在系统提供的UI界面上显示出来
最新长期支持版本9.9.1
本文使用8.9.3-community
,最新版下载太慢了。
ps:
Sonar Qube在7.9版本中已经放弃了对MySQL的支持,并且建议在商业环境中采用PostgreSQL,那么安装Sonar Qube时需要依赖PostgreSQL。
拉取镜像
docker pull postgres
docker pull sonarqube:8.9.3-community
编写docker-compoe.yml
version: "3.1"
services:
db:
image: postgres
container_name: db
ports:
- 5432:5432
networks:
- sonarnet
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
sonarqube:
image: sonarqube:8.9.3-community
container_name: sonarqube
depends_on:
- db
ports:
- "9000:9000"
networks:
- sonarnet
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
networks:
sonarnet:
driver: bridge
启动容器
docker-compose up -d
日志报错记录
2023.06.13 03:19:42 INFO es[][o.e.n.Node] initialized
2023.06.13 03:19:42 INFO es[][o.e.n.Node] starting ...
2023.06.13 03:19:42 INFO es[][o.e.t.TransportService] publish_address {127.0.0.1:40954}, bound_addresses {127.0.0.1:40954}
2023.06.13 03:19:42 INFO es[][o.e.b.BootstrapChecks] explicitly enforcing bootstrap checks
ERROR: [1] bootstrap checks failed. You must address the points described in the following [1] lines before starting Elasticsearch.
bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
ERROR: Elasticsearch did not exit normally - check the logs at /opt/sonarqube/logs/sonarqube.log
2023.06.13 03:19:42 INFO es[][o.e.n.Node] stopping ...
2023.06.13 03:19:42 INFO es[][o.e.n.Node] stopped
2023.06.13 03:19:42 INFO es[][o.e.n.Node] closing ...
2023.06.13 03:19:42 INFO es[][o.e.n.Node] closed
2023.06.13 03:19:42 WARN app[][o.s.a.p.AbstractManagedProcess] Process exited with exit value [es]: 78
2023.06.13 03:19:42 INFO app[][o.s.a.SchedulerImpl] Process[es] is stopped
2023.06.13 03:19:42 INFO app[][o.s.a.SchedulerImpl] SonarQube is stopped
sysctl -p
可以选择 maven 集成或者使用 sonar-scanner
进行代码质量分析。
<profile>
<id>sonarid>
<activation>
<activeByDefault>trueactiveByDefault>
activation>
<properties>
<sonar.login>adminsonar.login>
<sonar.password>你的密码sonar.password>
<sonar.host.url>http://192.168.1.190:9000sonar.host.url>
properties>
profile>
mvn sonar:sonar
下载 Sonar-scanner,为匹配SonarQube服务版本,本文选择下载4.6.x Linux版本版本。
上传到服务器并解压缩
unzip sonar-scanner-cli-4.6.2.2472-linux.zip
mv sonar-scanner-4.6.2.2472-linux sonar-scanner
测试使用sonar-scanner检测代码
在项目目录下执行指令
~/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=test -Dsonar.login=a29d38cf824b24d9e495e4a714879deb10ced30e -Dsonar.projectKey=linux-scanner -Dsonar.java.binaries=target/
Dsonar.sources
:扫描资源目录
Dsonar.projectname
:指定项目的名称
Dsonar.projectKey
:项目键,唯一标识符
Dsonar.login
:设置账户token
Dsonar.java.binaries
:指定编译生成的 Java 二进制文件的位置
Jenkins继承SonarQube实现代码扫描需要先下载整合插件:SonarQube Scanner
截止本段落位置,各架构关系图为
懂得都懂,不做介绍。
下载相关资源:️友情链接
拖拽到Linux并解压:
tar -zxvf harbor-offline-installer-v2.3.4.tgz -C /usr/local/
修改Harbor配置文件:
启动
./install.sh
构建镜像和发布镜像到harbor都需要使用到docker命令。设置Jenkins容器内部直接采用宿主机的Docker,节省点资源。当然,Jenkins里也可以安装docker。
chown root:root /var/run/docker.sock
chmod o+rw /var/run/docker.sock
version: "3.1"
services:
jenkins:
image: jenkins/jenkins:2.401.1-lts
container_name: jenkins
ports:
- 8080:8080
- 50000:50000
volumes:
- ./data/:/var/jenkins_home/
- /usr/bin/docker:/usr/bin/docker
- /var/run/docker.sock:/var/run/docker.sock
- /etc/docker/daemon.json:/etc/docker/daemon.json
部署项目需要通过Publish Over SSH插件,让目标服务器执行命令。
为了方便一次性实现拉取镜像和启动的命令,推荐采用脚本文件的方式。
添加脚本文件到目标服务器,再通过Publish Over SSH插件让目标服务器执行脚本即可。
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
containerId=`docker ps -a | grep ${project_name} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
docker stop $containerId
docker rm $containerId
echo "Delete Container Success"
fi
imageId=`docker images | grep ${project_name} | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
docker rmi -f $imageId
echo "Delete Image Success"
fi
docker login --username admin --password-stdin < ~/my_password.txt $harbor_url
docker pull $imageName
docker run -d -p $port:$port --name $project_name $imageName
echo "Start Container Success"
echo $project_name