Understanding Continuous Integration and Delivery
Software Development Life Cycle (SDLC)
The SDLC represents the entire workflow of planning, coding, testing, and releasing software. Typical phases include:
- Requirement Analysis: Gathering feasibility data, budget estimates, and project goals.
- System Design: Defining architecture, UI/UX layouts, and project milestones.
- Implementation: Developers write code based on design specs.
- Verification: QA teams perform functional, load, and security testing.
- Maintenance: Ongoing updates, bug fixes, and feature additions based on user feedback.
Waterfall vs. Agile Models
The Waterfall model follows a strictly linear path. While simple to understand, it creates heavy documentation overhead and delivers the product only at the very end, increasing risk.
| Pros | Cons |
|---|---|
| Simple structure | High documentation overhead |
| Clear phase transitions | High risk due to late delivery |
| Defined checkpoints | Poor adaptability to changing requirements |
Agile development focuses on iterative and incremental progress. Enstead of one massive release, the work is broken into small cycles (sprints).
- Iterative: Repeatedly refining the product through short cycles (e.g., building a simple prototype before a complex final version).
- Incremental: Delivering functional pieces one by one (e.g., releasing one feature module at a time).
Benefits include early return on investment (ROI) and reduced risk since feedback is gathered early.
Continuous Integration (CI) Defined
CI is the practice of merging developer code into a shared repository multiple times a day.
Core Components:
- Version Control System: Git or SVN acting as the source of truth.
- Automated Pipeline: Scripts that handle code checkout, compilation, testing, and packaging without manual intervention.
- CI Server: Tools like Jenkins that orchestrate the workflow.
Advantages:
- Early detection of bugs, reducing fix costs.
- Automated repetitive tasks (build/test).
- Always having a deployable artifact ready.
Setting Up the Jenkins Environment
Installing Jenkins
Option A: YUM Repository
wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo --no-check-certificate
rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
yum -y install jenkins
Option B: RPM Package
wget https://pkg.jenkins.io/redhat-stable/jenkins-2.190.1-1.1.noarch.rpm
rpm -ivh jenkins-2.190.1-1.1.noarch.rpm
Configuration:
Edit /etc/sysconfig/jenkins:
JENKINS_USER="root"
JENKINS_PORT="16060"
Set permissions and restart:
chown -R root:root /var/lib/jenkins
chown -R root:root /var/cache/jenkins
systemctl restart jenkins
If Java is missing, create a symlink:
ln -s /usr/local/jdk/bin/java /usr/bin/java
Essential Plugins
Install these via Manage Jenkins > Manage Plugins:
- Maven Integration: For building Java projects.
- Docker: To manage container lifecycles.
- GitLab: For repository integration.
- Publish Over SSH: To deploy artifacts to remote servers.
Tooling Setup (Git, Maven, Docker)
Git Installation:
yum -y install git
git version
Maven Configuration:
Extract the binary and set environment variables in /etc/profile:
export MAVEN_HOME=/usr/local/maven/apache-maven-3.3.9
export PATH=$PATH:$MAVEN_HOME/bin
Docker Installation:
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce
systemctl enable docker && systemctl start docker
Private Docker Registry
Launch a local registry to store images:
docker run -d -p 5000:5000 --name local_registry -v /usr/local/docker/registry:/var/lib/registry registry:latest
Configure the Docker client to trust the insecure registry by editing /lib/systemd/system/docker.service:
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.200.100:5000
Reload and restart:
systemctl daemon-reload
systemctl restart docker.service
Production Pipeline Configuration
Infrastructure Services
MySQL Deployment:
docker pull mysql:5.7
docker run -di --name=mysql_db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root mysql:5.7
Job Scheduler (XXL-Job):
- Update
application.propertiesto point to the MySQL instance. - Create a
Dockerfile:
FROM java:8u111
COPY xxl-job-admin-2.2.0-SNAPSHOT.jar /app.jar
CMD java -jar /app.jar
EXPOSE 8888
- Build and run:
docker build -t xxl-job-admin:2.2.0 .
docker run -di --name=xxl-job-admin -p 8888:8888 xxl-job-admin:2.2.0
Multi-Environment Strategy
Define profiles in the parent pom.xml to switch between Dev, Test, and Prod.
<profiles>
<profile>
<id>dev</id>
<activation><activeByDefault>true</activeByDefault></activation>
<build>
<filters><filter>maven_dev.properties</filter></filters>
</build>
</profile>
<profile>
<id>prod</id>
<build>
<filters><filter>maven_prod.properties</filter></filters>
</build>
</profile>
</profiles>
Example maven_prod.properties:
datasource.url=jdbc:mysql://52.82.20.5:33066/leadnews_admin?useUnicode=true
nacos.server=192.168.200.130:8848
Spring Boot application.yml usage:
spring:
datasource:
url: ${datasource.url}
username: ${datasource.username}
Build with a specific profile:
mvn package -P prod
Dockerizing Microservices
Maven Plugin Configuration (pom.xml):
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>docker_storage/${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
Generic Dockerfile:
FROM java:8
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENV JAVA_OPTS="-Xms256m -Xmx512m"
ENTRYPOINT java ${JAVA_OPTS} -jar /app.jar
Jenkins Pipeline Job
- Base Dependency Build: Create a Jenkins job to pull code and run
clean install -Dmaven.test.skip=true. - Service Deployment (e.g.,
leadnews-admin):- Build Step (Maven):
clean install -Dmaven.test.skip=true -P prod dockerfile:build -f heima-leadnews-admin/pom.xml - Post-build Shell Script: Clean up old containers and run new ones using
hostnetwork mode for connectivity.
- Build Step (Maven):
if [ -n "$(docker ps -a -f name=heima-$JOB_NAME --format '{{.ID}}' )" ]; then
docker rm -f $(docker ps -a -f name=heima-$JOB_NAME --format '{{.ID}}' )
fi
docker image prune -f
docker run -d --net=host --name heima-$JOB_NAME docker_storage/heima-$JOB_NAME
Remote Deployment via Registry
To deploy to a remote server, push the image to the private registry first.
Push Script:
image_tag=$docker_registry/docker_storage/heima-$JOB_NAME
docker tag docker_storage/heima-$JOB_NAME $image_tag
docker push $image_tag
docker rmi $image_tag
Remote Pull & Run Script:
docker pull $docker_registry/docker_storage/heima-$JOB_NAME
docker rm -f $(docker ps -a -f name=heima-$JOB_NAME --format '{{.ID}}' )
docker run -d --net=host --name heima-$JOB_NAME $docker_registry/docker_storage/heima-$JOB_NAME
Frontend Deployment (Nginx)
- Install Nginx from source or repo.
- Build Frontend: Modify API gateway paths and run build scripts to generate the
distfolder. - Nginx Config: Serve static files and proxy API requests.
http {
upstream backend_gateway {
server localhost:6001;
}
server {
listen 80;
location / {
root /root/workspace/admin/dist;
index index.html;
}
location ~/service_6001/(.*) {
proxy_pass http://backend_gateway/$1;
}
}
}
Build Triggers
Configure Jenkins to build automatically:
- Remote Trigger: Access
http://<jenkins-url>/job/<job-name>/build?token=<token>. - Cron Jobs: Use syntax like
H 18 * * *(Daily at 6 PM) in the Build Periodically section. - Poll SCM: Checks the repository for changes at intervals (not recommended due to overhead).