- 데브옵스 CI/CD
- Gitlab(무료 버전 및 유료 버전)
- 젠킨스
- GitLab+Jenkins 기반 CI\CD의 신속한 구현
- 백엔드 프로젝트 패키징 및 배포 방법
- 스프링 부트 메이븐 플러그인
- 메이븐 의존성 플러그인
- 메이븐 공식 홈페이지 플러그인
- maven-jar-플러그인
- maven 개인 서버에 jar 패키지 업로드
- ELK 로그 수집
- FileBeat+Logstash+ES를 사용하여 분산 로그 수집 실현
- maven(logstash-logback-encoder) + Logstash +ES를 사용하여 분산 로그 수집 실현
데브옵스 CI/CD
데브옵스:
- 즉, 개발(development)과 운영(operations and maintenance)의 합성어로 응용 프로그램이나 소프트웨어 엔지니어링 개발 사이의 커뮤니케이션, 협업 및 협력을 촉진하기 위해 사용되는 프로세스, 방법 및 시스템 그룹을 총칭하는 용어입니다. 기술 운영 및 품질 보증 QA 부서 통합
CI/CD:
- CI는 개발자를 위한 자동화된 프로세스인 지속적인 통합을 의미합니다. 성공적인 CI는
새로운 코드 변경이 정기적으로 빌드, 테스트 및 공유 저장소(예: Git 또는 SVN)로 병합됨을 의미합니다. - CD는 지속적인 제공 및 지속적인 배포를 나타냅니다. 성공적인 CD는 운영자가
공유 저장소에서 최신 제품 사본을 지속적으로 얻을 수 있고 최신 제품 사본을 서버에 올바르게 업데이트할 수 있음을 의미합니다.
Gitlab(무료 버전 및 유료 버전)
- GitLab은 기업에서 가장 일반적으로 사용되는 프라이빗 코드 웨어하우스 솔루션입니다.
- GitLab은 무료 CE 커뮤니티 에디션과 유료 EE 엔터프라이즈 에디션으로 구분되는 오픈 소스 프로젝트입니다.
- GitLab은 많은 백그라운드 서비스를 배포해야 하며 일반적으로 단일 시스템의 메모리가 4G보다 낮지 않아야 하는 것이 좋습니다. 구성이 너무 낮으면 이상한 문제가 많이 발생합니다.
- Linux 서버에는 여러 서비스가 미리 설치되어 있어야 합니다
yum install -y curl policycoreutils-python openssh-server
. 이미 설치되어 있는 경우 이 단계를 생략할 수 있습니다. - GitLab 설치 패키지를 가져옵니다. GitLab 커뮤니티 버전 다운로드 주소
https://packages.gitlab.com/gitlab/gitlab-ce
. 전자 상거래 프로젝트에 사용되는 Linux 서버를 다운로드하도록 선택할 수 있습니다.gitlab-ce-15.1.0-ce.0.el7.x86_64.rpm
- GitLab Execute를 설치하여 설치
rpm -Uvh gitlab-ce-15.1.0-ce.0.el7.x86_64.rpm
시작 - 설치가 완료된 후 GitLab을 처음 실행하기 전에 구성 초기화 작업을 수행해야 합니다.
gitlab-ctl reconfig
이 과정은 오랜 시간이 걸립니다 - gitlab-ctl 명령을 사용하여 gitlab 서비스를 작동
gitlab-ctl reconfigure
하고 gitlab을 재구성합니다.
gitlab-ctl start
gitlab 시작 gitlab
gitlab-ctl stop
중지 gitlab
gitlab-ctl restart
다시 시작
gitlab-ctl status
gitlab 서비스 상태 보기
gitlab-ctl tail
gitlab 서비스 로그 보기 - 서비스가 시작되면 gitlab 서비스에 접근할 수 있습니다. 기본 서비스 포트는 포트 80입니다. 기본 사용자 이름과 비밀번호는
root/123456입니다(일반적으로 로그인 후 기본 비밀번호를 즉시 변경하는 것이 좋습니다). - 액세스 주소 및 포트(기본적으로만 액세스 가능)를 수정하고 /etc/gitlab/gitlab.rb 구성 파일을 수정하고 그 안에 있는 external_url 속성을 수정할 수 있습니다.
젠킨스
Jenkins는 기업에서 가장 일반적으로 사용되는 자동 배포 소프트웨어입니다. 다운로드 주소는 https://www.jenkins.io/download/입니다.
LTS(장기 지원) 버전의 war 패키지 배포를 다운로드하는 것이 좋습니다.jenkins.war
- JDK 설치 필요 - Jenkins를 실행하려면 JDK 환경 지원이 필요합니다. 현재 Jenkins는 JDK11 버전 사용을 권장합니다.
- Jenkins 시작 - 시작 명령
nohup java -jar jenkins.war --httpPort=8080 &
포트는 기본적으로 포트 8080입니다. - 첫 번째 시작 프로세스 중에 Jenkins는 로그 파일에 기본 관리자 암호를 인쇄합니다.
xxxxxxxxxxxxxxxxxxxxxxx
- 시작이 완료되면 Jenkins의 프런트 엔드 관리 페이지를 방문할 수 있으며
http://x.x.x.x:8080/
처음 방문하는 경우 프런트 엔드 페이지에서 일부 초기화 작업을 안내합니다. 예를 들어 시작 로그에 있는 admin 사용자의 기본 암호를 입력해야 합니다. - 일부 플러그인 설치 안내 및 나중에 플러그인을 설치할 수도 있습니다.
- 플러그인 관리 페이지에는 Git, Git 클라이언트, NodeJS 플러그인, Maven 통합 플러그인, 현지화: 중국어(간체) 중국어 플러그인이
Manage Jenkins-> Manage Plugins
포함됩니다 - 다운로드가 완료된 후 일부 플러그인을 적용하려면 다시 시작해야 합니다. Jenkins를 다시 시작하는 방법은 브라우저에서 다시 시작 인터페이스에 직접 액세스하는 것입니다.
- 여러 기본 구성 요소를 구성하려면
- Mange Jenkins->Global ToolConfiguration 페이지에 들어가 Maven, Git 및 NodeJS 구성 요소를 구성해야 합니다.
- yum -install git을 사용하여 git 클라이언트를 설치합니다.
- Maven 및 NodeJS 플러그인, 공식 웹 사이트로 이동하여 해당 압축 패키지를 다운로드하고 압축을 푼 후 bin 하위 디렉토리를 환경 변수로 구성할 수 있습니다.
GitLab+Jenkins 기반 CI\CD의 신속한 구현
- 메이븐 프로젝트 만들기
- 프로젝트 빌드 및 배포 프로세스 구성
- 소스코드 관리 부분은 해당 git 웨어하우스 주소, git 사용자명과 비밀번호, git branch를 설정한다.
- 빌드 트리거 - 선택적으로 Poll SCM 옵션을 구성합니다. 이 옵션은 Git 코드 웨어하우스를 정기적으로 스캔할 수 있습니다.
- 빌드 환경 섹션에서 JDK 버전을 선택하는 것이 좋습니다.
- 빌드 섹션에서 실행해야 하는 컴파일 스크립트를 선택할 수 있습니다.
- 루트 폼
pom.xml
pacakge -Dmaven.test.skip=true
비슷한mvn package -Dmaven.test.skip=true
- 프론트엔드 프로젝트라면 Nodejs
npm run build
명령어 로 빌드해야 합니다.
- 루트 폼
- 빌드가 완료되면 백엔드 프로젝트의 각 모듈의 대상 디렉토리에 실행 가능한 패키지가 생성됩니다. 이때
Jenkins를 사용하여 이러한 Jar 패키지를 원격 서버에 배포하고 직접 실행할 수 있습니다.- SSH 서버 대상 서버
- 전송 세트 소스 파일은 Jar 주소를 실행합니다. 대상 루트 경로에서 검색 시작
xx/tarter/xx-exec.jar
- 접두사 제거 접두사를 사용하지 마십시오. 해당 jar 패키지만 전달됨을 나타냅니다.
xx/tarter
- 디렉토리 제거 원격 서버의 대상 주소
/xxx
- exec 명령 원격 서버에서 실행되는 시작 스크립트
- 후단
ps -ef | grep *demo* | grep -v grep | awk '{print $2}' | xargs kill -9 nohup java -jar ../../xx-exec.jar > /app/xxx/xxx.log 2 > &1 %
- 프런트 엔드
nginx -s reload
- 후단
- 코드 품질 감지 Blue Ocean 플러그인
- 태스크 파이프라인
- MeterSphere는 자동화된 인터페이스 테스트를 완료합니다.
- 또는 SonarQube 서비스를 구축하고 jenkins를 통해 통합합니다. 이런 식으로 SonarQube 서비스를 코드 품질 검사에 사용할 수 있습니다.
- 가상화 배포를 위해 Docker 통합
백엔드 프로젝트 패키징 및 배포 방법
1. jar 패키지는 다음과 같이 spring-boot-maven-plugin에 의해 입력됩니다 所有的依赖都打在了一个包中, 包太大, 但是可以直接使用Java -jar指令执行
. 이렇게 큰 Jar 패키지를 컴파일하는 것은 시간이 많이 걸리고 네트워크에서 전송하는 것이 매우 번거로울 것입니다.사실 대부분의 종속 패키지는 jdbc, mybatis 등을 변경하지 않습니다.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.12.RELEASE</version>
<executions>
<!-- 不排除repackage, 打包会多大一次 将原始Maven打包的jar重命名为XXX.jar.original作为原始文件
包含:类文件和配置文件,还会包含应用所依赖的jar包以及Springboot启动相关类(loader等),以此来满足Springboot独立应用的特性 -->
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!-- 解决运行包不能被其他包依赖的问题 -->
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
2. maven-dependency-plugin은 모두 결합할 수 있으므로 依赖的jar包都放到export文件夹中
파일 target目录下的jar包只包含当前项目的源码
크기가 훨씬 작아집니다.
- 현재 프로젝트의 소스 코드
- 종속 jar 패키지
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<!-- 将依赖包放入export文件夹 -->
<outputDirectory>export</outputDirectory>
<excludeTransitive>false</excludeTransitive>
<stripVersion>true</stripVersion>
</configuration>
</execution>
</executions>
</plugin>
java -cp 指定Classpath 和 启动类
도구를 통해 종속성을 배포 및 추가하는 방법rsync
#!/bin/sh
#执行jar包
RUN_LIBS=""
#依赖jar包 自行制定目录
SUPPORT_LIBS=""
RUN_LIB_PATH="/app/lib"
SUPPORT_LIB_PATH="/app/support"
#加载程序包
for i in ${RUN_LIB_PATH}/* ; do
RUN_LIBS=${RUN_LIBS}:$i
done
#加载依赖包
for i in ${SUPPORT_LIB_PATH}/* ; do
SUPPORT_LIBS=${SUPPORT_LIBS}:$i
done
#整合classpath
CLASSPATH=${RUN_LIBS}:${SUPPORT_LIBS}
export CLASSPATH
#调用java指令执行。-D输入参数 java中可以用 System.getProperties读取。同时指定执行入口类 SpringBootApplication 这是一个典型的Springboot的执行方式。
java -Xdebug -Xnoagent -Djava.compiler=NONE - Xrunjdwp:transport=dt_socket,server=y,address=27899,suspend=n -cp $CLASSPATH - Dspring.profiles.active=prod com.demo.DemoAdminApplication -D user.timezone=GMT+08 1>demo-admin.out 2>demo-admin.err & echo Start App Success!
3. 메이븐 공식 홈페이지 플러그인
https://maven.apache.org/plugins/index.html
- Maven 리포지토리의 최신 커밋 레코드를 출력할 수 있는 changelog 플러그인
- checkstyle 및 pmd 플러그인은 코드를 정적으로 확인할 수 있습니다.
- javadoc 플러그인은 프로젝트 문서를 인쇄할 수 있으며 pdf 플러그인을 사용하여 프로젝트 문서의 pdf 버전을 인쇄할 수도 있습니다.
- 일부 ant 스크립트를 실행하는 Antrun 플러그인(오래된 프로그래머는 ant에 익숙해야 함)
- pmd 정적 코드 검사 도구 https://maven.apache.org/plugins/maven-pmd-plugin/
Pmd는 자체 규칙을 정의할 수 있습니다 https://maven.apache.org/plugins/maven-pmd-plugin/examples/multi-module-config.html
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.19</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>aggregate-pmd</goal>
</goals>
</execution>
</executions>
</plugin>
4. maven-jar-plugin 툴킷은 Jar 패키지에 포함되어 있습니다.<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<artifactId>demo-common</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
</plugin>
</plugins>
</build>
5. maven-jar-plugin은 모든 코드를 하나의 jar 패키지로 출력하는 대신 다양한 모듈을 여러 개의 다른 jar 패키지로 출력합니다.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<!-- manifest配置信息 主要是可以配置主执行类。有主执行类,可以用java -jar直接执行。没有的话就需要指定执行类 -->
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>support/</classpathPrefix>
<mainClass>com.myapp.MyAppApplication</mainClass>
<!-- 可以按上面的方式自己配置,也可以指定MF文件打包。 -->
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>myapp1-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>myapp</classifier>
<includes>
<include>com/myapp/**</include>
<include>mybatis/**</include>
<include>templates/**</include>
<include>*.properties</include>
<include>dubbo.xml</include>
</includes>
</configuration>
</execution>
<execution>
<id>myapp2-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>myapp2</classifier>
<includes>
<include>com/myapp2/crawler/*</include>
<include>com/myapp2/crawler/*</include>
<include>com/myapp2/utils/**</include>
<include>log4j.properties</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
6. maven 사설 서버에 jar 패키지 업로드mvn deploy -P release
distributionManagement에서 스냅샷 스냅샷 라이브러리 및 릴리스 릴리스 라이브러리의 주소 구성
<distributionManagement>
<repository>
<id>maven-public</id>
<name>release</name>
<url>http://x.x.x.x:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-public-snapshot</id>
<name>snapshot</name>
<url>http://x.x.x.x:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
메이븐~/.m2/settings.xml
<server>
<id>nexus-releases</id>
<username>admin</username>
<password>admin123</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin123</password>
</server>
ELK 로그 수집
ELK 아키텍처: https://blog.csdn.net/menxu_work/article/details/126032167
Prometheus 및 Grafana 자동 모니터링: https://blog.csdn.net/menxu_work/article/details/125776376
FileBeat+Logstash+ES를 사용하여 분산 로그 수집 실현
maven(logstash-logback-encoder) + Logstash +ES를 사용하여 분산 로그 수집 실현
logstash 로그백 인코더
<!-- apm-toolkit-logback-1.x -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.9.0</version>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>6.3</version>
</dependency>
net.logstash.logback.appender.LogstashTcpSocketAppender<destination>logstash.localhost.com:5055</destination>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台 Appender -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 日志的格式化 -->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
<!-- https://skywalking.apache.org/docs/skywalking-java/latest/en/setup/service-agent/java-agent/application-toolkit-logback-1.x/ -->
<!-- 通过grpc上报日志到skywalking oap-->
<appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
<appender name="async" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>1024</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="console"/>
</appender>
<!-- add converter for %tid -->
<conversionRule conversionWord="tid" converterClass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackPatternConverter"/>
<!-- add converter for %sw_ctx -->
<conversionRule conversionWord="sw_ctx" converterClass="org.apache.skywalking.apm.toolkit.log.logback.v1.x.LogbackSkyWalkingContextPatternConverter"/>
<appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>logstash.localhost.com:5055</destination>
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>UTC</timeZone>
</timestamp>
<pattern>
<pattern>
{
"level": "%level",
"tid": "%tid",
"skyWalkingContext": "%sw_ctx",
"thread": "%thread",
"class": "%logger{1.}:%L",
"message": "%message",
"stackTrace": "%exception{10}"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>
<!-- 设置 Appender -->
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="grpc-log"/>
<appender-ref ref="async"/>
<appender-ref ref="logstash" />
</root>
</configuration>