<!-- vale off -->

# GitLab CI/CD 및 Envoy를 사용하여 Laravel 애플리케이션 테스트 및 배포

DETAILS:
**Tier:** Free, Premium, Ultimate
**Offering:** GitLab.com, Self-Managed, GitLab Dedicated

## 소개

GitLab은 애플리케이션을 지속적으로 통합하는 기능을 제공하며, 우리는 원하는 시점에 새 코드 변경 사항을 프로덕션 서버에 쉽게 배포할 수 있습니다.

이 튜토리얼에서는 [Laravel](https://laravel.com) 애플리케이션을 초기화하고 [Envoy](https://laravel.com/docs/master/envoy) 작업을 설정한 다음, [GitLab CI/CD](../index.md)[지속적 전달](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/)을 통해 테스트하고 배포하는 방법을 안내드리겠습니다.

기본적인 Laravel, Linux 서버 사용 및 GitLab 사용 방법을 알고 있다고 가정합니다.

Laravel은 PHP로 작성된 고품질 웹 프레임워크입니다.
[Laravel 문서](https://laravel.com/docs)를 비롯하여 일반적인 라우팅, 컨트롤러, 요청, 응답, 뷰 및 (블레이드) 템플릿 이외에도 캐시, 이벤트, 로컬라이제이션, 인증 등 다양한 서비스를 기본으로 제공합니다.

[Envoy](https://laravel.com/docs/master/envoy)는 PHP 기반의 SSH 작업 실행기로 사용됩니다.
이는 원격 서버에서 실행할 수 있는 작업을 설정하기 위해 깨끗하고 최소한의 [블레이드 구문](https://laravel.com/docs/master/blade)을 사용하며, 프로젝트를 저장소에서 클론하고, Composer 종속성을 설치하고, [Artisan 명령](https://laravel.com/docs/master/artisan)을 실행하는 등의 작업을 수행할 수 있습니다.

## GitLab에서 Laravel 앱 초기화

[Laravel 프로젝트를 새로 설치했다고 가정](https://laravel.com/docs/master/installation#installation)하고, 단위 테스트부터 시작하여 프로젝트에 Git을 초기화해 보겠습니다.

### 단위 테스트

Laravel의 모든 새로운 설치(현재 버전 8.0)에는 'Feature' 및 'Unit' 두 가지 유형의 테스트가 tests 디렉토리에 저장됩니다.
다음은 `test/Unit/ExampleTest.php`에서 가져온 단위 테스트 예시입니다:

```php
<?php

namespace Tests\Unit;

...

class ExampleTest extends TestCase
{
    public function testBasicTest()
    {
        $this->assertTrue(true);
    }
}

이 테스트는 주어진 값을 참으로 단언하는 것과 같습니다.

Laravel은 기본적으로 PHPUnit을 사용하여 테스트합니다. vendor/bin/phpunit을 실행하면 녹색 결과가 표시됩니다:

vendor/bin/phpunit
OK (1 test, 1 assertions)

이 테스트는 나중에 GitLab CI/CD로 앱을 계속해서 테스트하는 데 사용될 것입니다.

GitLab으로 푸시

로컬에서 앱을 실행 중이므로, 이제 코드베이스를 원격 저장소에 푸시할 시간입니다. laravel-sample이라는 새 프로젝트를 GitLab에서 생성하겠습니다. 그 후, 프로젝트 홈페이지에서 표시된 명령 줄 지침에 따라 머신에서 저장소를 초기화하고 첫 번째 커밋을 푸시합니다.

cd laravel-sample
git init
git remote add origin git@gitlab.example.com:<USERNAME>/laravel-sample.git
git add .
git commit -m 'Initial Commit'
git push -u origin main

프로덕션 서버 구성

Envoy 및 GitLab CI/CD를 설정하기 전에 빠르게 프로덕션 서버가 배포 준비 상태인지 확인해보겠습니다. 저희는 우분투 16.04에 LEMP 스택(Linux, NGINX, MySQL, PHP)을 설치했습니다.

새 사용자 생성

웹 사이트를 배포하는 데 사용할 새로운 사용자를 만들고, Linux ACL을 사용하여 해당 사용자가 디렉터리 /var/www에 대한 읽기-쓰기-실행 권한을 부여해보겠습니다.

# deployer 사용자 생성
sudo adduser deployer
# /var/www 디렉터리에 대해 deployer 사용자에게 읽기-쓰기-실행 권한 부여
sudo setfacl -R -m u:deployer:rwx /var/www

만약 우분투 서버에 ACL이 설치되어 있지 않다면 다음 명령어를 사용하여 설치할 수 있습니다.

sudo apt install acl

SSH 키 추가

GitLab의 개인 저장소에서 프로덕션 서버로 앱을 배포하려면 먼저비밀번호 없는 새 SSH 키 쌍을 생성해야 합니다.

그 후, 해당 SSH 키를 사용하여 서버에 deployer 사용자로 SSH로 연결할 수 있도록 복사하여 배포 프로세스를 자동화할 수 있습니다.

# 서버의 deployer 사용자로 실행
#
# 공개 키의 내용을 authorized_keys에 복사
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
# 개인 키의 텍스트 블록 복사
cat ~/.ssh/id_rsa

이제, 해당 키를 GitLab 프로젝트의 CI/CD 변수로 추가해야 합니다. 프로젝트 CI/CD 변수는 사용자 정의 변수로, .gitlab-ci.yml 파일 외부에 저장되며 보안 목적으로 사용됩니다. 프로젝트의 설정 > CI/CD로 이동하여 변수 이름을 SSH_PRIVATE_KEY로, 값으로 앞서 복사한 개인 키를 추가하면 됩니다. 이후에는 .gitlab-ci.yml에서 이 변수를 사용하여 deployer 사용자의 비밀번호를 입력하지 않고 원격 서버에 쉽게 연결할 수 있습니다.

variables page

또한, 해당 공개 키를 프로젝트 > 설정 > 저장소에서 배포 키로 추가해야 합니다. 이렇게 하면 SSH 프로토콜을 통해 서버에서 저장소에 액세스할 수 있는 권한이 부여됩니다.

# 서버의 deployer 사용자로 실행
#
# 공개 키 복사
cat ~/.ssh/id_rsa.pub

제목 필드에 원하는 이름을 추가하고, 공개 키를 필드에 붙여넣으면 됩니다.

deploy keys page

이제, 서버에서 단순히 저장소를 복제하여 deployer 사용자가 해당 저장소에 액세스할 수 있는지 확인해봅시다.

# 서버의 deployer 사용자로 실행
#
git clone git@gitlab.example.com:<USERNAME>/laravel-sample.git

Are you sure you want to continue connecting (yes/no)?라는 메시지가 나오면 yes로 대답합니다. 이렇게 하면 GitLab.com이 알려진 호스트에 추가됩니다. ```

NGINX 구성

이제 웹 서버 구성이 public이 아닌 current/public을 가리키도록 확인해 봅시다.

다음과 같이 입력하여 기본 NGINX 서버 블록 구성 파일을 엽니다.

sudo nano /etc/nginx/sites-available/default

구성은 다음과 같아야 합니다.

server {
    root /var/www/app/current/public;
    server_name example.com;
    # 나머지 구성
}

/var/www/app/current/public에 있는 앱 이름을 앱 폴더의 이름으로 바꿀 수 있습니다.

Envoy 설정

이제 우리의 라라벨 앱은 프로덕션을 위해 준비되었습니다. 다음은 배포를 수행하기 위해 Envoy를 사용하는 것입니다.

Envoy를 사용하려면 먼저 라라벨에서 제공하는 지침을 사용하여 로컬 머신에 설치해야 합니다.

Envoy 작동 방식

Envoy의 장점은 Blade 엔진이 필요하지 않으며, 작업을 정의하기 위해 Blade 구문만 사용한다는 것입니다. 먼저 루트에 간단한 Envoy 작업이 정의된 Envoy.blade.php를 만들어 보겠습니다.

@servers(['web' => 'remote_username@remote_host'])

@task('list', ['on' => 'web'])
    ls -l
@endtask

상단의 @servers 지시문 내에 있는 web이라는 키를 포함한 배열이 있으며, 여기에는 서버 주소(예: deployer@192.168.1.1)가 값으로 포함됩니다. 그런 다음 @task 지시문 내에서 작업이 실행될 때 서버에서 실행해야 하는 bash 명령을 정의합니다.

로컬 머신에서 run 명령을 사용하여 Envoy 작업을 실행합니다.

envoy run list

우리가 이전에 정의한 list 작업을 실행해서, 이 명령은 서버에 연결하여 디렉터리 내용을 나열해야 합니다.

Envoy는 라라벨의 종속성이 아니기 때문에 어떤 PHP 애플리케이션에든 사용할 수 있습니다.

제로 다운타임 배포

생산 서버에 배포할 때마다, Envoy는 GitLab 리포지토리에서 앱의 최신 릴리스를 다운로드하고 미리보기의 릴리스로 교체합니다. Envoy는 이 작업을 다운타임 없이 수행하므로 배포 중에 누군가가 사이트를 검토할 수 있을 때 걱정할 필요가 없습니다. 우리의 배포 계획은 GitLab 리포지토리에서 최신 릴리스를 복제하고, Composer 종속성을 설치한 다음 새 릴리스를 활성화하는 것입니다.

@setup 지시문

배포 프로세스의 첫 번째 단계는 @setup 지시문 내에서 일련의 변수를 정의하는 것입니다. app을 애플리케이션 이름으로 변경할 수 있습니다.

...

@setup
    $repository = 'git@gitlab.example.com:<USERNAME>/laravel-sample.git';
    $releases_dir = '/var/www/app/releases';
    $app_dir = '/var/www/app';
    $release = date('YmdHis');
    $new_release_dir = $releases_dir .'/'. $release;
@endsetup

...
  • $repository는 우리 리포지토리의 주소입니다.
  • $releases_dir 디렉터리는 앱을 배포하는 위치입니다.
  • $app_dir은 서버에서 라이브로 사용되는 앱의 실제 위치입니다.
  • $release에는 날짜가 포함되어 있으므로 앱의 새 릴리스를 배포할 때마다 현재 날짜를 이름으로 하는 새 폴더를 얻습니다.
  • $new_release_dir는 작업을 더 깔끔하게 만들기 위해 사용되는 새 릴리스의 전체 경로입니다.

@story 지시문

@story 지시문은 단일 작업으로 실행할 수 있는 작업 목록을 정의할 수 있습니다. 여기서는 clone_repository, run_composer, update_symlinks라는 세 가지 작업이 호출됩니다. 이러한 변수는 우리의 작업 코드를 더 깔끔하게 만드는 데 사용됩니다.

...

@story('deploy')
    clone_repository
    run_composer
    update_symlinks
@endstory

...

이제 하나씩 이 세 작업을 만들어 보겠습니다.

리포지토리 복제

첫 번째 작업은 releases 디렉터리(없는 경우)를 만든 다음, 리포지토리의 main 브랜치(기본값)를 새 릴리스 디렉터리인 $new_release_dir에 복제합니다. releases 디렉터리는 모든 배포의 내용을 보관합니다.

...

@task('clone_repository')
    echo 'Cloning repository'
    [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
    git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
    cd {{ $new_release_dir }}
    git reset --hard {{ $commit }}
@endtask

...

프로젝트가 성장함에 따라 Git 히스토리가 시간이 지남에 따라 매우 길어질 수 있습니다. 릴리스마다 디렉터리를 만들고 있기 때문에 각 릴리스마다 프로젝트의 히스토리를 다운로드할 필요가 없을 수도 있습니다. --depth 1 옵션은 시스템 시간과 디스크 공간을 절약할 수 있는 좋은 솔루션입니다.

Composer를 사용하여 종속성 설치

알다시피, 이 작업은 새 릴리스 디렉터리로 이동한 다음 Composer를 실행하여 애플리케이션 종속성을 설치합니다:

...

@task('run_composer')
    echo "배포 시작 ({{ $release }})"
    cd {{ $new_release_dir }}
    composer install --prefer-dist --no-scripts -q -o
@endtask

...

새 릴리스 활성화

새 릴리스의 요구 사항을 준비한 후에 하는 일은 해당 디렉터리에서 storage 디렉터리를 제거하고 애플리케이션의 storage 디렉터리와 .env 파일을 새 릴리스로 향하는 두 가지 심볼릭 링크를 만드는 것입니다. 그런 다음, 앱 디렉터리에 current라는 이름으로 새 릴리스에 대한 다른 심볼릭 링크를 만들어야 합니다. current 심볼릭 링크는 항상 앱의 최신 릴리스를 가리킵니다:

...

@task('update_symlinks')
    echo "storage 디렉터리 링킹"
    rm -rf {{ $new_release_dir }}/storage
    ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage

    echo '.env 파일 링킹'
    ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env

    echo '현재 릴리스 링킹'
    ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
@endtask

보시다시피, ln 명령어에 -nfs 옵션을 사용했는데, 이는 storage, .env, current가 더 이상 이전 릴리스를 가리키지 않고, 강제로 새 릴리스를 가리키도록 하는 것을 나타냅니다(-nfsf는 강제를 의미합니다). 이것은 여러 번의 배포를 할 때의 경우입니다.

전체 스크립트

스크립트는 준비가 끝났지만, deployer@192.168.1.1를 귀하의 서버로 변경하고 /var/www/app을 앱을 배포하려는 디렉터리로 변경해야 합니다.

마지막으로, 우리의 Envoy.blade.php 파일은 다음과 같아야 합니다:

@servers(['web' => 'deployer@192.168.1.1'])

@setup
    $repository = 'git@gitlab.example.com:<USERNAME>/laravel-sample.git';
    $releases_dir = '/var/www/app/releases';
    $app_dir = '/var/www/app';
    $release = date('YmdHis');
    $new_release_dir = $releases_dir .'/'. $release;
@endsetup

@story('deploy')
    clone_repository
    run_composer
    update_symlinks
@endstory

@task('clone_repository')
    echo '저장소 복제중'
    [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
    git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
    cd {{ $new_release_dir }}
    git reset --hard {{ $commit }}
@endtask

@task('run_composer')
    echo "배포 시작 ({{ $release }})"
    cd {{ $new_release_dir }}
    composer install --prefer-dist --no-scripts -q -o
@endtask

@task('update_symlinks')
    echo "storage 디렉터리 링킹"
    rm -rf {{ $new_release_dir }}/storage
    ln -nfs {{ $app_dir }}/storage {{ $new_release_dir }}/storage

    echo '.env 파일 링킹'
    ln -nfs {{ $app_dir }}/.env {{ $new_release_dir }}/.env

    echo '현재 릴리스 링킹'
    ln -nfs {{ $new_release_dir }} {{ $app_dir }}/current
@endtask

배포하기 전에 수동으로 첫 번째 배포 시 서버의 /var/www/app 디렉터리에 애플리케이션 storage 폴더를 복사하는 것이 필요합니다. 이 작업을 수행하기 위해 Envoy 작업을 추가하고 싶을 수 있습니다. 또한 Laravel을 위한 프로덕션 환경 변수를 설정하기 위해 동일한 경로에 .env 파일을 생성합니다. 이들은 지속적인 데이터이며 모든 새 릴리스에 공유될 것입니다.

이제 envoy run deploy를 실행하여 앱을 배포해야 할 수 있겠지만, GitLab이 CI의 environments로 우리를 대신해서 처리할 수 있기 때문에 필요하지 않을 것입니다. 이는 이 튜토리얼의 이후에 설명될 것입니다.

이제 Envoy.blade.php를 커밋하고 main 브랜치로 푸시하는 시간입니다. 간단하게 유지하기 위해, 협업은 이 튜토리얼의 범위를 벗어나므로 피처 브랜치를 사용하지 않고 직접적으로 main에 커밋합니다. 실제 프로젝트에서는 팀이 Issue Trackermerge requests를 사용하여 코드를 브랜치 간에 이동시킬 수 있습니다:

git add Envoy.blade.php
git commit -m 'Envoy 추가'
git push origin main

GitLab을 통한 지속적 통합

우리의 앱은 GitLab에 준비되어 있으며 수동으로 배포할 수도 있습니다. 그러나 지속적 인도 방법을 사용하여 자동으로 실행하기로 나아가봅시다. 우리는 모든 커밋을 자동화된 테스트 세트로 확인하여 문제를 가장 빠른 시일에 인지한 후, 테스트 결과에 만족한다면 대상 환경에 배포할 수 있습니다.

GitLab CI/CD를 사용하면 도커 엔진을 사용하여 앱의 테스트 및 배포 프로세스를 처리할 수 있습니다. 도커에 익숙하지 않다면 자동 빌드 설정을 참조하십시오.

GitLab CI/CD를 사용하여 앱을 빌드, 테스트 및 배포하려면 작업 환경을 준비해야 합니다. 이를 위해 Laravel 앱이 실행하는 데 필요한 최소 요구 사항을 갖춘 도커 이미지를 사용할 것입니다. 또한 다른 방법도 있지만, 빌드가 느리게 실행될 수 있으며 더 빠른 옵션을 사용하는 것이 바람직하지 않습니다.

컨테이너 이미지 만들기

앱의 루트 디렉토리에 다음 내용의 Dockerfile을 만들어 보겠습니다.

# Set the base image for subsequent instructions
FROM php:7.4

# Update packages
RUN apt-get update

# Install PHP and composer dependencies
RUN apt-get install -qq git curl libmcrypt-dev libjpeg-dev libpng-dev libfreetype6-dev libbz2-dev

# Clear out the local repository of retrieved package files
RUN apt-get clean

# Install needed extensions
# Here you can install any other extension that you need during the test and deployment process
RUN docker-php-ext-install mcrypt pdo_mysql zip

# Install Composer
RUN curl --silent --show-error "https://getcomposer.org/installer" | php -- --install-dir=/usr/local/bin --filename=composer

# Install Laravel Envoy
RUN composer global require "laravel/envoy=~1.0"

우리는 공식 PHP 7.4 도커 이미지를 추가했는데, 이는 PHP가 사전 설치된 Debian buster의 최소 설치로 우리의 사용 사례에 완벽히 적합합니다.

우리는 필요한 PHP 확장 기능을 설치하기 위해 docker-php-ext-install (공식 PHP 도커 이미지에서 제공)을 사용했습니다.

GitLab 컨테이너 레지스트리 설정

이제 Dockerfile이 준비되었으니, 이를 GitLab 컨테이너 레지스트리에 빌드하고 푸시해보겠습니다.

레지스트리는 이미지를 저장하고 태그를 지정하여 나중에 사용하는 장소입니다. 개발자들은 개인용이나 회사용 이미지, 또는 테스트에서만 사용되는 일회용 이미지를 유지하기를 원할 수 있습니다. GitLab 컨테이너 레지스트리를 사용하면 또 다른 서비스를 설정하고 관리할 필요가 없거나 공개 레지스트리를 사용할 필요가 없습니다.

GitLab 프로젝트 저장소에서 레지스트리 탭으로 이동하세요.

컨테이너 레지스트리 페이지 빈 이미지

이 탭을 볼 수 있으려면 프로젝트의 설정 > 일반 > 가시성, 프로젝트 기능, 권한 아래에 컨테이너 레지스트리를 활성화해야 할 수도 있습니다.

이제 컨테이너 레지스트리를 사용하려면 우리의 머신에서 GitLab 레지스트리에 로그인해야 합니다. 먼저 Docker가 우리의 머신에 설치되어 있는지 확인한 후, 다음 명령어를 실행하세요.

docker login registry.gitlab.com

그런 다음 이미지를 빌드하고 GitLab에 푸시할 수 있습니다.

docker build -t registry.gitlab.com/<USERNAME>/laravel-sample .

docker push registry.gitlab.com/<USERNAME>/laravel-sample

축하합니다! 첫 번째 도커 이미지를 GitLab 레지스트리에 푸시했습니다. 페이지를 새로고침하면 해당 이미지를 확인할 수 있을 것입니다.

이미지가 있는 컨테이너 레지스트리 페이지

또한 머신에서 직접 하는 대신 GitLab CI/CD를 사용하여 도커 이미지를 빌드하고 푸시할 수도 있습니다.

이 이미지를 .gitlab-ci.yml 구성 파일에서 테스트 및 배포 프로세스를 처리하는 데 사용할 것입니다.

이제 Dockerfile 파일을 커밋해 보겠습니다.

git add Dockerfile
git commit -m 'Dockerfile 추가'
git push origin main

GitLab CI/CD 설정

GitLab CI/CD를 사용하여 앱을 빌드하고 테스트하려면 우리 저장소의 루트에 .gitlab-ci.yml 파일이 필요합니다. 이는 Circle CI 및 Travis CI와 비슷하지만 내장된 GitLab과 유사합니다.

우리의 .gitlab-ci.yml 파일은 다음과 같을 것입니다.

default:
  image: registry.gitlab.com/<USERNAME>/laravel-sample:latest
  services:
    - mysql:5.7

variables:
  MYSQL_DATABASE: homestead
  MYSQL_ROOT_PASSWORD: secret
  DB_HOST: mysql
  DB_USERNAME: root

stages:
  - test
  - deploy

unit_test:
  stage: test
  script:
    - cp .env.example .env
    - composer install
    - php artisan key:generate
    - php artisan migrate
    - vendor/bin/phpunit

deploy_production:
  stage: deploy
  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: production
    url: http://192.168.1.1
  when: manual
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

이것은 받아들이기에 많이 너무 많이 이해하기 어렵죠? 단계별로 하나씩 진행해 보겠습니다.

이미지 및 서비스

런너(Runners).gitlab-ci.yml에서 정의한 스크립트를 실행합니다. 이미지(image) 키워드는 러너에게 사용할 이미지를 알려줍니다. 서비스(services) 키워드는 주 이미지에 연결된 추가 이미지를 정의합니다(주 이미지에 연결된 이미지입니다). 여기에서는 이전에 만든 컨테이너 이미지를 주 이미지로 사용하고 서비스로 MySQL 5.7를 사용합니다.

default:
  image: registry.gitlab.com/<USERNAME>/laravel-sample:latest
  services:
    - mysql:5.7

...

만약 여러 가지 PHP 버전과 데이터베이스 관리 시스템으로 앱을 테스트하려면 각 테스트 작업에 대해 다른 이미지(image)서비스(services) 키워드를 정의할 수 있습니다.

CI/CD 변수

GitLab CI/CD를 사용하면 CI/CD 변수를 작업에 사용할 수 있습니다. 우리는 기본적으로 superuser root가 생성된 상태로 MySQL을 데이터베이스 관리 시스템으로 설정했습니다.

그래서 우리는 MYSQL_DATABASE 변수를 데이터베이스 이름으로, MYSQL_ROOT_PASSWORD 변수를 root의 암호로 설정하여 MySQL 인스턴스의 구성을 조정해야 합니다. 공식 MySQL 도커 이미지에서 MySQL 변수에 대해 더 자세히 알아보세요.

또한 DB_HOSTmysql로, DB_USERNAMEroot로 설정하는 Laravel 특정 변수도 있습니다. 우리는 주 MySQL 이미지에 링크된 MySQL 도커 이미지를 사용하기 때문에 DB_HOST127.0.0.1이 아닌 mysql로 정의했습니다(작업에 서비스가 연결되는 방법 참조).

variables:
  MYSQL_DATABASE: homestead
  MYSQL_ROOT_PASSWORD: secret
  DB_HOST: mysql
  DB_USERNAME: root

첫 번째 작업으로 유닛 테스트

우리는 unit_test 작업을 실행할 때 스크립트(script) 키워드의 배열로 필요한 셸 스크립트를 정의했습니다.

이 스크립트들은 라라벨을 준비하기 위한 몇 가지 Artisan 명령어이며, 스크립트의 끝에서 PHPUnit을 사용하여 테스트를 실행할 것입니다.

unit_test:
  script:
    # 앱 종속성 설치
    - composer install
    # .env 설정
    - cp .env.example .env
    # 환경 키 생성
    - php artisan key:generate
    # 마이그레이션 실행
    - php artisan migrate
    # 테스트 실행
    - vendor/bin/phpunit

프로덕션으로 배포

deploy_production 작업은 앱을 프로덕션 서버에 배포합니다. Envoy로 앱을 배포하려면, 우리는 SSH 개인 키$SSH_PRIVATE_KEY 변수를 설정해야 합니다. 만약 SSH 키가 성공적으로 추가되었다면 Envoy를 실행할 수 있습니다.

이전에 언급한 바와 같이, GitLab은 지속적 배포(Continuous Delivery) 방법을 지원합니다. 환경(environment) 키워드는 GitLab에게 이 작업이 production 환경으로 배포해야 한다는 것을 알려줍니다. url 키워드는 GitLab 환경 페이지에서 앱에 대한 링크를 생성하는 데 사용됩니다. rules:if 키워드는 작업이 main 브랜치를 빌드할 때에만 실행되어야 한다는 것을 GitLab CI/CD에게 알려줍니다. 마지막으로 when: manual은 작업을 자동으로 실행하는 것에서 수동 조치로 전환하는 데 사용됩니다.

deploy_production:
  script:
    # 빌드 환경에 개인 SSH 키 추가
    - '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'
    # Envoy 실행
    - ~/.composer/vendor/bin/envoy run deploy
  environment:
    name: production
    url: http://192.168.1.1
  when: manual
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

당신은 스테이징 환경을 위한 또 다른 작업을 추가하여 앱을 프로덕션으로 배포하기 전에 앱을 최종으로 테스트할 수 있습니다.

GitLab CI/CD 활성화

GitLab CI/CD로 앱을 테스트하고 배포하는 데 필요한 모든 것을 준비했습니다. 이를 위해 .gitlab-ci.ymlmain 브랜치에 커밋하고 푸시하세요. 이렇게 하면 파이프라인이 트리거되며, 프로젝트의 파이프라인에서 라이브로 확인할 수 있습니다.

파이프라인 페이지

여기서 테스트(Test)배포(Deploy) 단계를 볼 수 있습니다. 테스트(Test) 단계에는 unit_test 빌드가 실행 중입니다. 빌드의 실행 결과를 보려면 해당 항목을 선택하세요.

파이프라인 페이지

코드가 성공적으로 파이프라인을 통과하면, 우리는 오른쪽에 있는 재생(play) 버튼을 선택하여 우리의 프로덕션 서버에 배포할 수 있습니다.

파이프라인 페이지 배포 버튼

배포 파이프라인이 성공적으로 통과하면 파이프라인 > 환경으로 이동하세요.

환경 페이지

모든 게 예상대로 작동하지 않는다면, 앱의 가장 최근 작동되는 버전으로 롤백할 수 있습니다.

환경 페이지

오른쪽에 지정된 외부 링크 아이콘을 선택하면, GitLab이 프로덕션 웹사이트를 엽니다. 배포가 성공적으로 완료되었으며 앱이 온라인 상태임을 확인할 수 있습니다.

Laravel Welcome 페이지

만약 배포 후에 프로덕션 서버 상의 애플리케이션 디렉토리 구조가 어떻게 되는지 궁금하다면, current, releases, storage와 같은 세 개의 디렉토리를 볼 수 있습니다. current 디렉토리는 최신 릴리스를 가리키는 심볼릭 링크입니다. .env 파일은 우리의 라라벨 환경 변수를 포함하고 있습니다.

프로덕션 서버 앱 디렉토리

current 디렉토리로 이동하면 애플리케이션의 내용을 볼 수 있습니다. .env 파일이 /var/www/app/.env 파일을 가리키고 있고, 또한 storage/var/www/app/storage/ 디렉토리를 가리키고 있음을 알 수 있습니다.

프로덕션 서버 current 디렉토리

결론

우리는 GitLab CI/CD를 구성하여 자동화된 테스트를 수행하고 지속적인 전달 방법을 사용하여 Laravel 애플리케이션을 코드베이스에서 직접 프로덕션 환경에 배포했습니다.

또한 Envoy는 사용자 정의 bash 스크립트를 작성하지 않고 Linux 마법을 사용하여 응용 프로그램을 배포하는 데 큰 도움이 되었습니다.