赞
踩
该项目是一个入门CICD-Demo,它由以下几部分组成:
通过这个Demo,你可以:
项目地址:CICD-Blog
测试网址:www.ningyu.ink
这个Dockerfile分为四个构建阶段:
# syntax=docker/dockerfile:1 FROM eclipse-temurin:17-jdk-jammy as base WORKDIR /blog COPY .mvn/ .mvn COPY mvnw pom.xml ./ RUN chmod +x mvnw RUN ./mvnw dependency:resolve COPY src ./src FROM base as dev EXPOSE 8080 RUN chmod +x mvnw CMD ["./mvnw", "spring-boot:run"] FROM base as build RUN ./mvnw package FROM eclipse-temurin:17-jre-jammy as prod EXPOSE 8080 COPY --from=build /blog/target/blog-*.jar /blog.jar CMD ["java", "-jar", "/blog.jar"]
该文件包含两个profiles:
docker compose --profiles dev up -d --build
在本地运行docker compose --profiles prod up -d --build
在服务器运行services: blog-dev: build: context: . target: dev container_name: blog ports: - "8080:8080" environment: - MYSQL_URL=jdbc:mysql://mysql/blog?serverTimezone=Asia/Shanghai volumes: - ./:/blog networks: mysql-net: depends_on: - mysql-dev profiles: - dev blog-prod: build: context: . target: prod container_name: blog environment: - MYSQL_URL=jdbc:mysql://mysql/blog?serverTimezone=Asia/Shanghai volumes: - ./:/blog networks: mysql-net: nginx-net: depends_on: - mysql-prod profiles: - prod mysql-dev: image: mysql:8.0 container_name: mysql ports: - "3306:3306" environment: - MYSQL_ROOT_PASSWORD=123456 - MYSQL_DATABASE=blog volumes: - mysql_data:/var/lib/mysql - mysql_config:/etc/mysql/conf.d - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql networks: mysql-net: profiles: - dev mysql-prod: image: mysql:8.0 container_name: mysql environment: - MYSQL_ROOT_PASSWORD=123456 - MYSQL_DATABASE=blog volumes: - mysql_data:/var/lib/mysql - mysql_config:/etc/mysql/conf.d - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql networks: mysql-net: profiles: - prod nginx-dev: image: nginx container_name: nginx ports: - "80:80" - "443:443" environment: - NGINX_HOST=ningyu.ink - NGINX_PORT=80 volumes: - ./nginx/templates:/etc/nginx/templates - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/ssl:/etc/nginx/ssl networks: nginx-net: profiles: - dev nginx-prod: image: nginx container_name: nginx ports: - "80:80" - "443:443" environment: - NGINX_HOST=ningyu.ink - NGINX_PORT=80 volumes: - ./nginx/templates:/etc/nginx/templates - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ./nginx/ssl:/etc/nginx/ssl networks: nginx-net: profiles: - prod volumes: mysql_data: mysql_config: networks: mysql-net: driver: bridge nginx-net: driver: bridge
Nginx的所有配置都在项目下的nginx目录下并通过三个挂在绑定挂载到了容器中:
其中:
由于本项目还没有前端代码,所以在访问时直接代理到了后端接口,具体配置如下:
http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 443 ssl; server_name ningyu.ink; ssl_certificate /etc/nginx/ssl/ningyu.ink_bundle.crt; ssl_certificate_key /etc/nginx/ssl/ningyu.ink.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; location / { proxy_pass http://blog:8000/test/log; } } server { listen 80; server_name ningyu.ink; return 301 https://$host$request_uri; } }
其中我们将80端口转发到了443端口,并且在配置文件中可以直接使用容器名称进行网络代理(前提是在同一网络下):
MySQL的compose.yml构建语法是这样的:
mysql-prod:
image: mysql:8.0
container_name: mysql
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=blog
volumes:
- mysql_data:/var/lib/mysql
- mysql_config:/etc/mysql/conf.d
- ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
mysql-net:
profiles:
- prod
它做了以下事情:
MYSQL_ROOT_PASSWORD
指定了root密码MYSQL_DATABASE
指定了容器运行后需要创建的数据库/sql/init.sql
的初始化脚本,该脚本用于在数据库中创建应用需要的表可以看到application.yml内容是这样的:
server:
port: 8080
spring:
application:
name: blog
datasource:
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:123456}
url: ${MYSQL_URL:jdbc:mysql://localhost/blog?serverTimezone=Asia/Shanghai}
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
其中通过${}
读取的环境变量值都是在compose.yml中定义的,这极大增强了灵活性。
GitHub Action通过.github/workflows
下的deploy.yml
起作用,其文件内容是这样的:
name: Deploy on: push: branches: - master jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy to tencent server uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.REMOTE_HOST}} key: ${{ secrets.SERVER_SSH_KEY }} username: ${{ secrets.REMOTE_USER }} script: | # 切换到主目录 cd ~ || exit # 判断是否安装了Docker,如果没有则使用官方提供的脚本安装Docker if ! command -v docker &> /dev/null ; then curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh fi # 判断是否拉拉取了代码,没有拉取则拉取 if [ ! -d "./blog" ]; then git clone https://github.com/chinesecooly/blog.git fi # 进入工作目录 cd blog || exit # 更新代码 git pull # 运行prod环境下的构建,并且每次都重新构建镜像 docker compose --profile prod up -d --build
它的作用如下:
with
语句中指定的),这三个参数存储在以下位置,需要根据自己的服务器配置。docker compose --profile prod up -d --build
命令部署项目,--profile
选项指定了选取的profile
,-d
选项指定了容器在后台运行,--build
选项指定了每次运行这条指令时都重新构建镜像,这保证了我们每次更新的代码都能署到服务器上以下Controller是该项目提供的一个测试Controller,他完成了一次接收请求、操作数据库、做出响应的过程:
@Slf4j @RestController @RequestMapping("/test") public class TestController { @Resource private TestMapper testMapper; @GetMapping("/log") public Result log() { Test test = new Test(); test.setMsg("a get request"); test.setData(LocalDateTime.now()); testMapper.insert(test); return Result.success(test); } }
项目部署后访问一下是这样的:
我们在dev
修改一下代码:
@Slf4j @RestController @RequestMapping("/test") public class TestController { @Resource private TestMapper testMapper; @GetMapping("/log") public Result log() { Test test = new Test(); test.setMsg("a get request after one push"); test.setData(LocalDateTime.now()); testMapper.insert(test); return Result.success(test); } }
合并到master
并推送,等待几秒再次访问一下:
以下是GitHub Actions两次执行的记录:
通过本文你可以扩展更复杂的应用场景,如有不明白或建议,可留言联系我,如果可以的话点个关注,谢谢。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。