使用云服务器搭建自己的CI/CD环境(docker+Jenkins)

概要:本篇介绍使用宝塔Linux面板操作云服务器,搭建Jenkins和docker用于部署项目+持续集成。介绍如何通过docker部署spring boot项目和前端vue项目。

环境准备

准备云服务器

我使用的是阿里的云服务器,配置上个人的话使用两核 2G/40G 3M带宽足够了,如果想提高Jenkins持续集成的速度的话,建议上4G。

博主在购买服务器的时候使用的是centos7,如果选错系统也没关系,可以从阿里的管理平台上更换

  • 更换系统

点击你的实例

在一览页面找到系统信息点击更换

服务器准备好之后就可以开始操作了,这里我选择使用宝塔Linux面板来操作我的服务器(选择自己习惯的即可)

  • centos安装宝塔的脚本
yum install -y wget && wget -O install.sh https://download.bt.cn/install/install_6.0.sh && sh install.sh ed8484bec

其他系统也可自行进入宝塔官网寻找脚本

宝塔面板下载,免费全能的服务器运维软件 (bt.cn)

下载完宝塔之后,使用它提供的账号密码登录,注意账号密码不要丢失了

记得在你的安全组里开放端口给自己电脑的ip(注意!你要是把电脑带到家/公司你的ip会变,记得再加一遍)

运行Jenkins

  • 下载Jenkins

注意!推荐不要使用docker运行Jenkins,因为后面Jenkins要用docker命令来部署项目,我之前用docker版的Jenkins搞半天跑不起来项目,贼麻烦,干脆用运行它的war包的方式来运行Jenkins。版本选择2.361.4以后的!!!

链接:https://pan.baidu.com/s/106QmmARIKqDai_R98z2ByA
提取码:bja4

官网其他版本 War Jenkins Packages

版本选择2.361.4以后是因为它的插件不支持低版本的Jenkins,后面下插件很麻烦。

  • 下载jdk11(或更高版本)

**为什么不是jdk8?**因为Jenkins能支持jdk8的版本它的插件不支持,不过后续也需要下载jdk8来运行部署的项目。

wget https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_linux-x64_bin.tar.gz

记得自己选择一个目录解压,方便找文件

tar -xzvf jdk-11.0.14_linux-x64_bin.tar.gz

配置环境变量

vi /etc/profile
export JAVA_HOME=/你的目录/jdk-11
export CLASSPATH=$JAVA_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin
source /etc/profile

进入war包对应的目录运行脚本把Jenkins跑起来

nohup java -jar jenkins.war --ajp13Port=-1 --httpPort=10000 --prefix=/jenkins >> ./jenkins.log 2>&1

检查一下运行状态(跑起来后关闭终端也没事)

netstat -tln | grep 10000

记得在安全组开放10000端口给自己

访问 http://你的服务器IP:10000/jenkins

无法访问?

大概率是centos的防火墙阻止了访问

  • 查看10000端口是否开放了访问
firewall-cmd --query-port=10000/tcp

如果是no,那么就开放访问或者直接关闭防火墙

  • 开放访问
firewall-cmd --add-port=10000/tcp --permanent
firewall-cmd --reload
  • 或者直接永久关闭防火墙
systemctl disable firewalld

再次访问,看到以下页面即代表成功

找不到密码没关系,在jenkins.war同一个目录下有jenkins.log文件,查看该文件即可拿到密码

然后继续->安装推荐的插件->创建管理员账户就完成啦!

准备项目运行的环境

  • 下载docker

由于我是用宝塔linux面板,它里面就有按钮,点击即可下载,这里我就跳过了

  • 下载jdk8,maven,node.js(记得自己找个目录下)

jdk8(不用配环境变量)

链接:https://pan.baidu.com/s/13a3xw4qx476AyBEAO9_UvQ
提取码:gc5e

maven直接用命令下就行了

wget https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
tar -xvf apache-maven-3.8.6-bin.tar.gz

配置maven的环境变量

vi /etc/profile
export MAVEN_HOME=/你的目录/apache-maven-3.8.6
export PATH=$PATH:$MAVEN_HOME/bin
source /etc/profile

node.js (16.20.2)

链接:https://pan.baidu.com/s/14vBK4hNjZGvfB5P-x53sIw
提取码:5c5e

推荐使用软连接的方式配置环境变量

ln -s /你的目录/nodejs/bin/node /usr/local/bin/
ln -s /你的目录/nodejs/bin/npm /usr/local/bin/

由于我前端使用cnpm命令,所以我还要下载cnpm

npm install -g cnpm --registry=https://registry.npm.taobao.org

配置cnpm的软连接

ln -s /你的目录/nodejs/bin/cnpm /usr/local/bin/

检查一下命令是不是生效了

node -v
npm -v
cnpm -v
docker version
java --version

确保你的命令可以使用,因为在部署项目时需要执行shell脚本

为什么java --version 是jdk11

因为已经配了jdk11,jdk8只是用来跑后端项目的,在Jenkins里面配置一下jdk8的目录就行。

在Jenkins->系统管理-> 全局工具配置找到jdk

把刚刚下载的jdk8的路径填上

搭建CI/CD环境

搭建后端

我的项目使用到了mysql 8,我打算使用docker来运行mysql,方便管理

  • 运行mysql容器

先创建bridge!!这一步很重要,因为不同的容器通信使用bridge会很方便

docker network create -d bridge mybridge

拉取mysql的镜像,并运行容器(密码是root,也可自行配置MYSQL_ROOT_PASSWORD=?)

docker pull mysql:latest
docker run -it --network mybridge -d -p 3306:3306 --privileged=true -v /home/mysql/conf:/etc/mysql/conf.d -v/home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql mysql

记得去阿里的服务器管理页面在安全组开放3306端口,如果你的centos系统没关闭防火墙,则要配置一下3306端口允许访问

firewall-cmd --query-port=3306/tcp
firewall-cmd --add-port=3306/tcp --permanent
firewall-cmd --reload

如果你还使用了其他技术,拉取对应的docker镜像,然后运行容器即可,记得加上**–network mybridge**

  • 创建新的任务

  • 然后直接到build step这一步

选择执行shell

mvn clean package -DskipTests
cp 项目打包.jar docker
cd docker
docker ps -a | grep 名字 | awk '{print $1}' | xargs -i docker stop {} | xargs -i docker rm {}
docker images | grep 名字 | awk '{print $3}' | xargs -i docker rmi {}
docker build -f Dockerfile -t "名字:prod" . --no-cache
docker run -it --network mybridge -d -p 9090:9090 --name 名字 名字:prod

这里的脚本意思是,先打包,然后拷贝jar包到项目根目录下的docker目录,进入docker目录,先删除(之前的)容器和镜像,再通过docker目录下的Dockerfile构建镜像,然后运行镜像。记得加**–network mybridge**(之前创建的bridge)

这里我的项目里面的Dockerfile长这样

# jre
FROM openjdk:8-jre-alpine

# author
MAINTAINER author

# 接受传参
ENV JAVA_OPIS ""

# 添加jar包到容器中(注意!请先执行shell拷贝jar包到docker目录下)
ADD 项目打包.jar /home/app.jar

EXPOSE 9090

CMD ["sh", "-c", "echo \"****** 运行命令: java -jar ${JAVA_OPIS} /home/app.jar --spring.profiles.active=prod\" & java -jar ${JAVA_OPIS} /home/app.jar --spring.profiles.active=prod"]

因为使用了bridge,所以你需要修改一下yml配置文件(将host改成docker容器名)

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://mysql的docker容器名:3306/test?useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: root

其他配置同理

Q&A

  • 我的后端项目成功跑起来了,怎么接口无法访问?答:记得在安全组开放你配置的端口,还有配置centos防火墙
  • 为什么我后端的项目访问不了mysql的docker容器?答:两个容器在运行时推荐使用自己创建的bridge的方式通信,通过加–network mybridge的方式
  • 为什么我在运行jar包时–spring.profiles.active=prod失效?答:检查一下你的启动类有没有加上args
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);// args没加的话参数就传不进去
    }
}
  • 怎么查看日志?答:
docker ps -a  # 查看所有正在运行的容器
docker logs -f --since "2024-01-02" 29ac5d06777a # 查看指定容器id指定日期的日志

搭建前端

我使用的是Jenkinsfile+Dockerfile的方式配置,在项目根目录先创建Docker文件夹

  • 在Jenkins新建任务

Dockerfile

# 拉取nginx基础镜像
FROM nginx:1.21.1

# 维护者信息
MAINTAINER author

# 将dist文件中的内容复制到 `/usr/share/nginx/html/` 这个目录下面
COPY dist/  /usr/share/nginx/html/
# 用本地配置文件来替换nginx镜像里的默认配置
COPY nginx/nginx.conf /etc/nginx/nginx.conf

# 对外暴漏的端口号
# [注:EXPOSE指令只是声明容器运行时提供的服务端口,给读者看有哪些端口,在运行时只会开启程序自身的端口!!]
EXPOSE 5173

# 启动nginx容器
CMD ["nginx", "-g", "daemon off;"]

.dockerignore

node_modules

在项目根目录创建Jenkinsfile

pipeline {
    agent any
    environment {
        APP_NAME = '项目名'
        APP_IMAGE = '镜像名'
        APP_PORT = 5173
    }

    stages {

        stage('vue环境准备') {
            steps {
                sh """
                # 拷贝dist到Docker目录下
                cp -r dist Docker/
                """
            }
        }

        stage('构建Docker镜像') {
            steps {
                sh """
                    # 删除旧容器
                    docker ps -a | grep ${APP_NAME} | awk '{print \$1}' | xargs -i docker stop {} | xargs -i docker rm {}
                    # 删除旧镜像
                    docker images | grep ${APP_NAME} | awk '{print \$3}' | xargs -i docker rmi {}
                    # 进入Docker目录
                    cd Docker
                    # 构建镜像
                    docker build -f Dockerfile -t ${APP_IMAGE} . --no-cache
                """
            }
        }

        stage('运行容器') {
            steps {
                sh """
                    docker run --network mybridge -d -p ${APP_PORT}:5173 --restart=always --name ${APP_NAME} ${APP_IMAGE}
                """
            }
        }

    }
}

nginx.conf的内容(经供参考)

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    # include /etc/nginx/conf.d/*.conf;

    server {
        listen       5173;  # 你的前端项目端口
        server_name  localhost; # 服务器地址或绑定域名,可以写localhost

        #charset koi8-r;
        #access_log  /var/log/nginx/host.access.log  main;

        # =========================================================
        # ================== ↓↓↓↓↓↓ start ↓↓↓↓↓↓ ==================
        # =========================================================


        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
            # 此处的 @router 实际上是引用下面的转发,否则在 Vue 路由刷新时可能会抛出 404
           try_files $uri $uri/ @router;
       }


       # 由于路由的资源不一定是真实的路径,无法找到具体文件
       # 所以需要将请求重写到 index.html 中,然后交给真正的 Vue 路由处理请求资源
       location @router {
           rewrite ^.*$ /index.html last;
       }


		# 配置代理服务器,访问前缀有/api/的接口讲会去除前缀api交给代理服务器进行处理
		location ^~/api/ {
		    proxy_pass http://后端镜像名:端口/;
            proxy_set_header Host $host;
            proxy_set_header  X-Real-IP        $remote_addr;
            proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header X-NginX-Proxy true;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            client_max_body_size    100m;
            proxy_connect_timeout 90;
            proxy_read_timeout 90;
            proxy_send_timeout 90;
        }





        # =========================================================
        # ================== ↑↑↑↑↑↑ end ↑↑↑↑↑↑ ==================
        # =========================================================

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

    }
}

Q&A

  • 为什么Jenkinsfile里面是直接拷贝dist文件夹而不是使用npm build命令?答:因为我的两核2G服务器扛不住这个命令,构建会报错javascript heap out of memory,所以我只能在自己的电脑上build然后git推送上去

  • 为什么项目跑起来了但是页面无法访问?答:在安全组开放端口,在centos配置防火墙。

  • 502错误?答:可能是nginx.conf文件有问题

  • 访问不到后端的接口?答:如果是通过docker的bridge的话,你需要在nginx.conf的location里面配置proxy_pass,主机名是后端docker容器名字,记得检查你的docker容器运行命令有没有加–network mybridge。

其他搭建方式(仅供参考,我还没实践以下方式)

  • 后端-通过docker+shell直接运行jar包的方式
# 解决jenkins默认自动终止shell产生的进程问题
BUILD_ID=dontKillMe
# 打包
mvn clean package -DskipTests
cd target
# 先停掉旧服务
ps -ef | grep demo-0.0.1-SNAPSHOT.jar | grep -v grep | awk '{print "kill -15 "$2}' | sh
# 再运行新服务
nohup java -jar demo-0.0.1-SNAPSHOT.jar > app.log 2>&1
  • 前端-docker+执行shell的方式(不通过Jenkinsfile的方式)
cnpm i
cnpm run build:prod
cp -r dist/ Docker/
cd Docker
docker ps -a | grep APP_NAME | awk '{print $1}' | xargs -i docker stop {} | xargs -i docker rm {}
docker images | grep APP_NAME | awk '{print \$3}' | xargs -i docker rmi {}
docker build -f Dockerfile -t APP_NAME . --no-cache
docker run -d -p 81:80 --restart=always --name APP_NAME APP_IMAGE
  • 18
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
DockerJenkins是两个流行的工具,都被广泛应用于DevOps和持续集成/持续交付(CI/CD)领域。Docker是一个开源的容器化平台,可以轻松地打包、交付和运行应用程序。Jenkins是一个流行的开源持续集成工具,可以自动化构建、测试和部署应用程序。 使用DockerJenkins可以搭建一个高效的CI/CD环境。通过将Jenkins作为Docker容器运行,可以轻松地扩展Jenkins服务器,并且可以方便地使用Docker构建工具来构建和测试应用程序。下面是使用DockerJenkins搭建CI/CD环境的基本步骤: 1. 安装DockerJenkins 首先需要在服务器上安装DockerJenkins。安装方法可以参考官方文档或者网上的教程。安装完毕后,启动DockerJenkins服务。 2. 配置JenkinsJenkins中,需要安装一些插件,例如Docker Pipeline插件和Docker插件。这些插件可以帮助JenkinsDocker集成,实现自动化构建和部署。 3. 创建Jenkins Pipeline 使用Jenkins Pipeline功能,可以将应用程序的构建和部署流程定义为一个Jenkinsfile文件。在Jenkinsfile文件中,可以指定Docker镜像的构建和部署操作。例如,可以使用Dockerfile文件构建Docker镜像,并使用Docker Compose部署应用程序。 4. 构建Docker镜像 使用Dockerfile文件定义应用程序的环境和依赖,然后使用Docker构建工具构建Docker镜像。可以使用Jenkins Pipeline中的Docker构建步骤来构建Docker镜像。 5. 部署应用程序 使用Docker Compose工具可以轻松地部署应用程序。可以使用Jenkins Pipeline中的Docker Compose步骤来部署应用程序。 6. 集成测试 使用Docker Compose可以轻松地在本地环境中进行集成测试。可以使用Jenkins Pipeline中的Docker Compose步骤来运行集成测试。 7. 自动化部署 使用Jenkins的自动化部署功能,可以在代码提交后自动构建和部署应用程序。可以使用Jenkins Pipeline中的Git插件来实现自动化部署。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fan_11235813

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值