Gitlab: PHP项目CI/CD实践

目录

1 说明

2 CI/CD

2.1 部署方式一:增量部署

2.1.1 目标服务器准备 

2.2.2 Gitlab及Envoy脚本

2.2 部署方式二:镜像构建与部署

2.2.1 推送到私有化容器仓库

准备工作

脚本

要点

2.2.2 推送到hub.docker.com

准备工作

脚本

3 参考:


1 说明

  • 以一个laravel blog项目为例,做dev分支的CI/CD实践
  • 结合laravel envoy工具做多个远程服务器部署,分两种方式:A. 增量部署 B.镜像构建与部署

服务器:

SiteServerIP站点目录
team1-prj2.dev.iahost001.dev.ia192.168.0.130/www/wwwroot/team1-prj2.dev.ia
team1-prj2.dev.iahost002.dev.ia192.168.0.131/www/wwwroot/team1-prj2.dev.ia

2 CI/CD

2.1 部署方式一:增量部署

通过Lavavel/Envoy和git拉取新版本文件进行部署

2.1.1 目标服务器准备 
  • php8.2, 安装所需扩展,务必在cli下测试是否正常, 有些被disable的functions要打开
  • composer self-update, 兼容php8.2
  • 使用Laravel/Envoy分发部署,确保Envoy.blade.php是utf8格式文件
  • 站点目录结构
    root@host001:/www/wwwroot/team1-prj2.dev.ia# tree -d -L 3 ./
    ./
    ├── current -> /www/wwwroot/team1-prj2.dev.ia/releases/default
    ├── releases
    │   └── default
    │       ├── app
    │       ├── bootstrap
    │       ├── config
    │       ├── database
    │       ├── public
    │       ├── resources
    │       ├── routes
    │       ├── storage -> /www/wwwroot/team1-prj2.dev.ia/storage
    │       ├── tests
    │       └── vendor
    └── storage├── app│   └── public├── framework│   ├── cache│   ├── sessions│   ├── testing│   └── views└── logs
    

说明:

team1-prj2.dev.ia应用目录
team1-prj2.dev.ia/releases版本发布目录,这里只设置了一个default目录,也可根据需要做日期变量发布
team1-prj2.dev.ia/current

链接到最新版本,被nginx访问的站点目录路径

current -> /www/wwwroot/team1-prj2.dev.ia/releases/default/

team1-prj2.dev.ia/storage

链接到最新版本的应用数据保存目录,如:日志,缓存等

storage -> /www/wwwroot/team1-prj2.dev.ia/storage

team1-prj2.dev.ia/.dev

.dev文件是运维人员建立的服务器定制环境文件,不进入仓库,链接到项目同名文件

.env -> /www/wwwroot/team1-prj2.dev.ia/.env*

team1-prj2.dev.ia/releases/default/.gitlab-ci.ymlgitlab 部署脚本
team1-prj2.dev.ia/releases/default/Envoy.blade.phpenvoy 部署脚本

nginx配置

server
{listen 80;server_name team1-prj2.dev.ia;index index.php index.html index.htm default.php default.htm default.html;root /www/wwwroot/team1-prj2.dev.ia/current/public;#CERT-APPLY-CHECK--START# 用于SSL证书申请时的文件验证相关配置 -- 请勿删除include /www/server/panel/vhost/nginx/well-known/team1-prj2.dev.ia.conf;#CERT-APPLY-CHECK--END#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则#error_page 404/404.html;#SSL-END#ERROR-PAGE-START  错误页配置,可以注释、删除或修改#error_page 404 /404.html;#error_page 502 /502.html;#ERROR-PAGE-END#PHP-INFO-START  PHP引用配置,可以注释或修改include enable-php-82.conf;#PHP-INFO-END#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效include /www/server/panel/vhost/rewrite/team1-prj2.dev.ia.conf;#REWRITE-END#禁止访问的文件或目录location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md){return 404;}#一键申请SSL证书验证目录相关设置location ~ \.well-known{allow all;}#禁止在证书验证目录放入敏感文件if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {return 403;}location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${expires      30d;error_log /dev/null;access_log /dev/null;}location ~ .*\.(js|css)?${expires      12h;error_log /dev/null;access_log /dev/null;}location / {try_files $uri $uri/ /index.php?$query_string;}access_log  /www/wwwlogs/team1-prj2.dev.ia.log;error_log  /www/wwwlogs/team1-prj2.dev.ia.error.log;
}
2.2.2 Gitlab及Envoy脚本

.gitlab-ci.yml

# default:
#  image: edbizarro/gitlab-ci-pipeline-php:7.4
#default:
# image: bennybi/php8.2
# image: bennybi/php7.4stages:- test- deploy.init_ssh: &init_ssh |which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )eval $(ssh-agent -s)echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/nullmkdir -p ~/.sshchmod 700 ~/.ssh[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/configcache:key: ${CI_COMMIT_REF_SLUG}paths:- vendor/unit_test:stage: testtags:- phpscript:- cp .env.test .env- composer install- composer global require "laravel/envoy"- php artisan key:generate- php artisan migrate- vendor/bin/phpunitdeploy_dev:stage: deploytags:- phpenvironment:name: devurl: http://team1-prj2.dev.iascript:- *init_ssh- vendor/bin/envoy run deploy --branch="$CI_COMMIT_BRANCH" --commit="$CI_COMMIT_SHA"rules:- if: $CI_COMMIT_BRANCH == "dev"deploy_live:stage: deploytags:- phpscript:- *init_ssh- vendor/bin/envoy run deploy --commit="$CI_COMMIT_SHA"environment:name: liveurl: http://team1-prj2.dev.iawhen: manualrules:- if: $CI_COMMIT_BRANCH == "live"

Envoy.blade.php

@servers(['local' => 'deployer@host001.dev.ia','staging' => 'deployer@host002.dev.ia'])@setup$repository = 'git@host001.dev.ia:dev1/team1-prj2.git';$releases_dir = '/www/wwwroot/team1-prj2.dev.ia/releases';$app_dir = '/www/wwwroot/team1-prj2.dev.ia';$release = 'default';$new_release_dir = $releases_dir .'/'. $release;$user = get_current_user();
@endsetup@story('deploy', ['on' => ['local','staging']])sync_repositoryrun_composerupdate_symlinks
@endstory@task('sync_repository')echo "Current User: {{$user}}, branch:{{$branch}}, commit:{{$commit}}"if [ -d "{{$new_release_dir}}" ]; thenecho 'Pulling repository'cd {{ $new_release_dir }}git checkout {{ $branch }}git fetchgit reset --hard HEADgit merge origin/{{ $branch }}elseecho 'Cloning repository'[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}git clone --branch {{ $branch }}  --single-branch --depth 1 {{ $repository }} {{ $new_release_dir }}cd {{ $new_release_dir }}git reset --hard {{ $commit }}git config --global --add safe.directory '*'fi
@endtask@task('run_composer')echo "Starting deployment ({{ $release }})"cd {{ $new_release_dir }}composer install --prefer-dist --no-scripts -q -o
@endtask@task('update_symlinks')if [ ! -d "{{ $app_dir }}/current" ]; thenecho "Linking storage directory"{{-- rm -rf {{ $new_release_dir }}/storage  --}}mv {{ $new_release_dir }}/storage {{ $app_dir }}ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storageecho 'Linking .env file'ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.envecho 'Linking current release'ln -nfs {{ $new_release_dir }} {{ $app_dir }}/currentchmod 775 -Rf {{ $releases_dir }}fichmod 775 -Rf {{ $new_release_dir }}/storage{{-- chown deployer:www -Rf {{ $new_release_dir }}/.git  --}}
@endtask
2.2 部署方式二:镜像构建与部署
说明:
  1. 应用文件在build_image阶段,打包在镜像文件中,并推送到私有化的项目镜像仓库
  2. lavavel应用所需.env,不进入代码仓库,而是通过 -v 映射到具体路径部署,如示例代码中的 "-v /data0/Projects/team1-prj1/.env:/app/.env",防止敏感参数外泄
  3. 实例化后作为微服务容器,暴露8181端口提供外部访问
2.2.1 推送到私有化容器仓库
准备工作

-  新建项目team1-prj1,初始化git 仓库为:http://host001.dev.ia:18181/dev1/team1-prj1.git

-  建好容器仓库(见前文相关部分)

-  需要在Admin Area->CI/CD->Variables添加docker访问用户变量

$LOCAL_REGISTRY_LOGIN = your docker username
$LOCAL_REGISTRY_PASSWORD
脚本

 项目中添加Dockerfile 文件,这里用到的原型镜像是我之前定制的php8.2

FROM bennybi/php8.2:latestWORKDIR /appRUN apt-get update -y && apt-get install -y openssl zip unzip git
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# RUN docker-php-ext-install pdo mbstringCOPY .env.example .env
COPY . /app
RUN composer install --no-interaction --prefer-dist --optimize-autoloader# Run any additional commands specific to Laravel
RUN php artisan config:cache
RUN php artisan route:cache
RUN php artisan view:cacheCMD php artisan serve --host=0.0.0.0 --port=8181
EXPOSE 8181

 .gitlab-ci.yml

default:image: docker:19.03.8services:- mysql:5.7before_script:- docker infovariables:# DOCKER_IMAGE_TAG: 'bennybi/team1-prj1'APP_NAME: 'team1-prj1'REGISTRY_URL: 'http://host001.dev.ia:5050'DOCKER_IMAGE_TAG: 'host001.dev.ia:5050/dev1/team1-prj1:1.0.0'# DOCKER_IMAGE_TAG: 'host001.dev.ia:5050/dev1/team1-prj1'CONTAINER_IMAGE_NAME: ${DOCKER_IMAGE_TAG}# MYSQL_DATABASE: test# MYSQL_ROOT_PASSWORD: fa843c707ce26702# DB_HOST: host001.dev.ia# DB_USERNAME: developerstages:- test- build- deployunit_test:stage: testtags:- phpscript:- cp .env.test .env- composer install- php artisan key:generate- php artisan migrate- vendor/bin/phpunitbuild_image:stage: buildtags:- phpscript:- docker login ${REGISTRY_URL} -u $LOCAL_REGISTRY_LOGIN -p $LOCAL_REGISTRY_PASSWORD- docker build --output type=registry,oci-mediatypes=false --cache-from "${DOCKER_IMAGE_TAG}" -t "${DOCKER_IMAGE_TAG}" --push --provenance=false .# - docker push ${DOCKER_IMAGE_TAG}:latest- docker push ${DOCKER_IMAGE_TAG}rules:- if: $CI_COMMIT_BRANCH == "dev"deploy_dev:stage: deploytags:- phpscript:- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'- eval $(ssh-agent -s)- ssh-add <(echo "$SSH_PRIVATE_KEY")- mkdir -p ~/.ssh- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'- ssh deployer@host002.dev.ia "docker login ${REGISTRY_URL} -u $LOCAL_REGISTRY_LOGIN -p $LOCAL_REGISTRY_PASSWORD && docker pull $CONTAINER_IMAGE_NAME && docker stop ${APP_NAME} || true && docker rm ${APP_NAME} || true && docker run --name ${APP_NAME} -d -p 8181:8181  -v /data0/Projects/${APP_NAME}/.env:/app/.env ${CONTAINER_IMAGE_NAME} && docker exec ${APP_NAME} php artisan config:cache || true"environment:name: devurl: http://team1-prj1.dev.ia# when: manualrules:- if: $CI_COMMIT_BRANCH == "dev"
要点

- 注意build时所需的参数,缺少会诱发错误: “Invalid tag: missing manifest digest”

We used the buildx flag “–output type=registry,oci-mediatypes=false” to generate a Docker v2.2 manifest list.  We could set the value to “true” and generate an OCI manifest index, but the GitLab UI will incorrectly display “Invalid tag: missing manifest digest”. 

 推送结果图示:

2.2.2 推送到hub.docker.com
准备工作

-  新建项目team1-prj1,初始化git 仓库为:http://host001.dev.ia:18181/dev1/team1-prj1.git

-  构建的镜像将push到hub.docker.com,因此需要在Admin Area->CI/CD->Variables添加docker访问用户变量

$DOCKER_LOGIN = your docker username
$DOCKER_PASSWORD 
脚本

Dockerfile 

同上 ...

.gitlab-ci.yml

default:image: docker:19.03.8services:- mysql:5.7before_script:- docker infovariables:MYSQL_DATABASE: testMYSQL_ROOT_PASSWORD: fa843c707ce26702DB_HOST: host001.dev.iaDB_USERNAME: developerstages:- test- build# - deployunit_test:stage: testtags:- phpscript:- cp .env.test .env- composer install- php artisan key:generate- php artisan migrate- vendor/bin/phpunitbuild_image:stage: buildvariables:DOCKER_IMAGE_TAG: 'bennybi/team1-prj1'tags:- phpscript:- docker build --cache-from "${DOCKER_IMAGE_TAG}" -t "${DOCKER_IMAGE_TAG}" .- docker login --username $DOCKER_LOGIN --password $DOCKER_PASSWORD# - docker run my-docker-image /script/to/run/tests- docker push ${DOCKER_IMAGE_TAG}:latestrules:- if: $CI_COMMIT_BRANCH == "dev"# deploy_dev:
#   stage: deploy
#   tags:
#     - php
#   script:
#     - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
#     - eval $(ssh-agent -s)
#     - ssh-add <(echo "$SSH_PRIVATE_KEY")
#     - mkdir -p ~/.ssh
#     - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
#     # - ~/.composer/vendor/bin/envoy run deploy --commit="$CI_COMMIT_SHA"
#   environment:
#     name: dev
#     url: http://team1-prj1.dev.ia
#   when: manual
#   rules:
#     - if: $CI_COMMIT_BRANCH == "dev"

3 参考:

- GitLab: automated build and publish of multi-platform container image with GitLab pipeline | Fabian Lee : Software Engineer

- https://jaumemule.medium.com/build-a-php8-0-fpm-gitlab-ci-cd-application-docker-google-cloud-5f2868e8370

- https://docs.gitlab.com/ee/ci/docker/using_docker_build.html

 - https://github.com/papertank/envoy-deploy/blob/master/readme.md

- https://warrickbayman.medium.com/zero-downtime-laravel-deployments-with-envoy-version-2-227c8259e31c

- Test and deploy Laravel applications with GitLab CI/CD and Envoy | GitLab

- GitLab CI/CD examples | GitLab

- 使用GitLab Runner为基于Laravel的PHP项目进行部署 

- GitLab CI/CD for Beginners [FREE Course] - DEV Community

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/521284.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis-Plus实现Service封装

文章目录 5.1 MP封装Service介绍5.1.1 说明5.1.2 实现流程5.1.3 核心API介绍 5.2 MP封装Service快速入门5.2.1 定义服务扩展接口5.2.2 定义服务实现5.2.3 测试测试 5.3 MP封装Service实现CRUD操作 5.1 MP封装Service介绍 5.1.1 说明 MybatisPlus为了开发更加快捷&#xff0c;…

华为“仓颉”不是中文编程:中文编程早有所属,势如破竹

“何时能见证中国自主研发的编程语言崛起&#xff1f;”这是我们这些对IT生态心怀关切的人常常深思的问题。 语言&#xff0c;作为文化的灵魂&#xff0c;总是与特定的环境和人群紧密相连。无论是中文还是英语&#xff0c;它们都不仅仅是交流的工具&#xff0c;更是各自文化背…

KBPC3510-ASEMI逆变器整流桥KBPC3510

编辑&#xff1a;ll KBPC3510-ASEMI逆变器整流桥KBPC3510 型号&#xff1a;KBPC3510 品牌&#xff1a;ASEMI 封装&#xff1a;KBPC-4 正向电流&#xff08;Id&#xff09;&#xff1a;35A 反向耐压&#xff08;VRRM&#xff09;&#xff1a;1000V 正向浪涌电流&#xff…

STM32学习7 按键扫描

STM32学习7 按键扫描 一、实验电路介绍二、按键GPIO初始化三、扫描原理1. GPIO引脚配置2. 状态轮询3. 按键状态检测4. 循环扫描的优缺点优点&#xff1a;缺点&#xff1a; 四、一次扫描与持续扫描五、代码实现1. 头文件定义2. 函数实现3. 主体函数 一、实验电路介绍 本实验使用…

广播

1.什么是广播 2.标准广播 BroadStandardActivity.java package com.tiger.chapter09;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.view.View;…

为什么不用 index 做 key?

“在 Vue 中&#xff0c;我们在使用 v-for 渲染列表的时候&#xff0c;为什么要绑定一个 key&#xff1f;能不能用 index 做 key&#xff1f;” 在聊这个问题之前我们还得需要知道 Vue 是如何操作 DOM 结构的。 虚拟DOM 我们知道&#xff0c;Vue 不可以直接操作 DOM 结构&am…

js小案例-表格隔行变色

运行效果: 代码演示: <!DOCTYPE html> <html><head><meta charset="utf-8" /><title>18-案例-表格隔行变色</title></head><body><table id="tab1" border="1" width="800" al…

北斗卫星引领智能油气管线革新

北斗卫星引领智能油气管线革新 现代化的油气管线系统已成为国家经济发展的重要基础设施&#xff0c;而北斗卫星则为这些管线注入了新的活力。北斗卫星作为中国自主研发的卫星导航定位系统&#xff0c;其准确度和稳定性在全球范围内享有盛誉。在智能化时代的背景下&#xff0c;…

【OpenGL实践02】glDrawElements的使用案例

目录 一、说明二、顶点顺序渲染和选择渲染2.1 基本方法函数2.2.顶点数据管理2.3 层级关系 三、测试EBO的代码四、总结五、后记 一、说明 我们常用的着色器绘制函数是glDrawArray和glDrawElements&#xff0c;glDrawArray我们已经使用的很熟练&#xff0c;不需要重提&#xff…

深入了解Python的eval函数:基础用法与潜在危险【第118篇—eval函数】

深入了解Python的eval函数&#xff1a;基础用法与潜在危险 在Python中&#xff0c;eval函数是一个强大而灵活的工具&#xff0c;它允许将字符串作为代码来执行。然而&#xff0c;虽然eval在某些情况下非常方便&#xff0c;但它也潜藏着一些潜在的危险&#xff0c;如果不小心使…

小火星露谷管理器 如何禁用管理器下载?

错误操作 当你在N网点击下载时&#xff0c;你可能会点击左边第一个按钮进行下载&#xff0c;如图&#xff1a; 然后你可能会看到这样的一个提示&#xff1a; 很多用户看着这个提示误以为小火星露谷管理器禁用了N网的下载。 正确操作 N网网页上的按钮MOD MANAGER DOWNLOAD翻…

海外IP代理应用:亚马逊使用什么代理IP?

代理IP作为网络活动的有力工具&#xff0c;同时也是跨境电商的必备神器。亚马逊作为跨境电商的头部平台&#xff0c;吸引了大量的跨境电商玩家入驻&#xff0c;想要做好亚马逊&#xff0c;养号、测评都需要代理IP的帮助。那么应该使用什么代理IP呢&#xff1f;如何使用&#xf…