216.73.216.26 TODAY : 1,879

PHP ์˜จ๋ผ์ธ ๊ฐ•์˜

 > 

PHP - ์ตœ์ƒ๊ธ‰

๐Ÿ“š PHP ์ตœ์ƒ๊ธ‰ - 4์ฃผ์ฐจ: CI/CD (์ง€์†์  ํ†ตํ•ฉ/์ง€์†์  ๋ฐฐํฌ) ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•- 03 PHP ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

๐Ÿ“š PHP ์ตœ์ƒ๊ธ‰ - 4์ฃผ์ฐจ: CI/CD (์ง€์†์  ํ†ตํ•ฉ/์ง€์†์  ๋ฐฐํฌ) ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์ถ•- 03 PHP ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

์ฃผ์š” ํ”„๋กœ๊ทธ๋žจ ์ŠคํŽ™

  • ํ‰์ : 10.0
  • ๋ผ์ด์„ ์Šค: free
  • ์šด์˜์ฒด์ œ:
  • ํŒŒ์ผ ํฌ๊ธฐ: 0

ํ”ผ๋“œ๋ฐฑ ๋ฐ ๋‹ค์šด๋กœ๋“œ

  • ์‚ฌ์šฉ์ž ํ‰์ : 10.0
  • ๋‹ค์šด๋กœ๋“œ ์ˆ˜: 1
  • ์กฐํšŒ์ˆ˜: 5

์ œ์กฐ์‚ฌ ๋ฐ ๋“ฑ๋ก ์ •๋ณด

  • ์ œ์ž‘์‚ฌ: LUZENSOFT
  • ๋“ฑ๋ก์ผ: 2025-10-15 14:14:23
  •  

- ์„ค๋ช…

#PHP์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ ์œ„ํ•œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„ ๊ฐœ์š”

uploadImage


์ง€๋‚œ ์‹œ๊ฐ„์—๋Š” #CI/CD ์˜ ๊ฐœ๋…๊ณผ ์ฃผ์š” ๋„๊ตฌ(GitLab CI/CD, GitHub Actions)์— ๋Œ€ํ•ด ํ•™์Šตํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ์ด๋ก ์„ ๋ฐ”ํƒ•์œผ๋กœ ์‹ค์ œ #PHP์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์— ์ ์šฉ ๊ฐ€๋Šฅํ•œ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์„ ์„ค๊ณ„ํ•˜๊ณ  ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ๊ฐœ๋ฐœ๋œ ์ฝ”๋“œ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ๋นŒ๋“œํ•˜๊ณ , ํ…Œ์ŠคํŠธํ•˜๋ฉฐ, ์ตœ์ข…์ ์œผ๋กœ ์šด์˜ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•˜๋Š” ์ผ๋ จ์˜ ์ž๋™ํ™” ๋‹จ๊ณ„๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ๋ชฉํ‘œ๋กœ ํ•˜๋Š” #CI/CDํŒŒ์ดํ”„๋ผ์ธ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฃผ์š” ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  1. ์ฝ”๋“œ ์ปค๋ฐ‹(Code Commit): ๊ฐœ๋ฐœ์ž๊ฐ€ Git ์ €์žฅ์†Œ์— ์ฝ”๋“œ๋ฅผ ํ‘ธ์‹œํ•ฉ๋‹ˆ๋‹ค

  2. ๋นŒ๋“œ(Build): #Composer ์˜์กด์„ฑ์„ ์„ค์น˜ํ•˜๊ณ , #Docker์ด๋ฏธ์ง€ ๋ฅผ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค

  3. ํ…Œ์ŠคํŠธ(Test): ๋‹จ์œ„ ํ…Œ์ŠคํŠธ, ์ •์  ๋ถ„์„(Linter), ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฒ€์‚ฌ ๋“ฑ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค

  4. ๋ฐฐํฌ(Deploy): ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผํ•œ #Docker์ด๋ฏธ์ง€ ๋ฅผ ์ปจํ…Œ์ด๋„ˆ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ํ‘ธ์‹œํ•˜๊ณ , ์šด์˜ ์„œ๋ฒ„์— ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค

์ด๋Ÿฌํ•œ ํŒŒ์ดํ”„๋ผ์ธ์„ ํ†ตํ•ด #PHP๊ฐœ๋ฐœ ํŒ€์€ ๋” ๋น ๋ฅด๊ณ  ์•ˆ์ •์ ์ธ ์†Œํ”„ํŠธ์›จ์–ด ๋ฆด๋ฆฌ์Šค๋ฅผ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



1. #CI/CD ํŒŒ์ดํ”„๋ผ์ธ ์„ค๊ณ„ ๋‹จ๊ณ„

uploadImage



1.1 Git ์ €์žฅ์†Œ ๋ฐ ๋ธŒ๋žœ์นญ ์ „๋žต


๊ฐ€์žฅ ๋จผ์ € #CI/CD ์˜ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ๋  Git ์ €์žฅ์†Œ์™€ ํšจ๊ณผ์ ์ธ ๋ธŒ๋žœ์นญ ์ „๋žต์„ ์ˆ˜๋ฆฝํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ค‘์•™ ์ €์žฅ์†Œ: GitHub, GitLab, Bitbucket ๋“ฑ

  • ๋ธŒ๋žœ์นญ ์ „๋žต: Git Flow, GitHub Flow ๋“ฑ ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ์™€ ํŒ€์˜ ํŠน์„ฑ์— ๋งž๋Š” ์ „๋žต์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ Pull Request(Merge Request)๊ฐ€ ์ƒ์„ฑ๋˜๊ฑฐ๋‚˜ main ๋ธŒ๋žœ์น˜์— ์ฝ”๋“œ๊ฐ€ ๋ณ‘ํ•ฉ๋  ๋•Œ #CI/CD ๊ฐ€ ํŠธ๋ฆฌ๊ฑฐ๋˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.


1.2 #Docker ๊ธฐ๋ฐ˜ ํ™˜๊ฒฝ ๊ตฌ์ถ•


#Docker ๋Š” #CI/CD ํŒŒ์ดํ”„๋ผ์ธ์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œ์™€ ๋ฐฐํฌ์˜ ์ผ๊ด€์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

  • #Dockerfile: #PHP์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ ์œ„ํ•œ ์ตœ์ ํ™”๋œ #Dockerfile ์„ ์ž‘์„ฑํ•˜์—ฌ, ํ•„์š”ํ•œ #PHP๋ฒ„์ „ , ํ™•์žฅ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์˜์กด์„ฑ ๋“ฑ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

  • #DockerCompose: ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์œ„ํ•ด ์›น ์„œ๋ฒ„(Nginx/Apache), #PHP-FPM, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(MySQL) ๋“ฑ์„ #DockerCompose ๋กœ ์ •์˜ํ•˜์—ฌ ์ผ๊ด€๋œ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” CI/CD ๊ณผ์ •์—์„œ๋„ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


1.3 ํ…Œ์ŠคํŠธ ์ „๋žต ์ˆ˜๋ฆฝ


์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋Š” #CI/CD ์˜ ์‹ ๋ขฐ์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค.

  • ๋‹จ์œ„ ํ…Œ์ŠคํŠธ(Unit Test): PHPUnit ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ํ•จ์ˆ˜๋‚˜ ํด๋ž˜์Šค์˜ ๋™์ž‘์„ ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.

  • ์ •์  ๋ถ„์„(Static Analysis): #PHPStan, #Psalm, PHP CS Fixer ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž ์žฌ์ ์ธ ๋ฒ„๊ทธ๋‚˜ ์ฝ”๋“œ ์Šคํƒ€์ผ ์œ„๋ฐ˜์„ ๋นŒ๋“œ ๋‹จ๊ณ„์—์„œ ๋ฏธ๋ฆฌ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.

  • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ(Integration Test): ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.



2. #CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌํ˜„ ์˜ˆ์‹œ (GitHub Actions)

uploadImage


์ด์ œ ์•ž์—์„œ ์„ค๊ณ„ํ•œ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ GitHub Actions๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ #PHP์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ ์œ„ํ•œ #CI/CDํŒŒ์ดํ”„๋ผ์ธ ์„ ๊ตฌํ˜„ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ .github/workflows/main.yml ํŒŒ์ผ์˜ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

YAML

name: PHP CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build_test:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.3' # ์‚ฌ์šฉํ•  PHP ๋ฒ„์ „
        extensions: pdo_mysql, zip, gd # ํ•„์š”ํ•œ PHP ํ™•์žฅ
        ini-values: post_max_size=256M, upload_max_filesize=256M
        tools: composer # Composer ์„ค์น˜ ํฌํ•จ

    - name: Get Composer Cache Directory
      id: composer-cache
      run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

    - name: Cache Composer dependencies
      uses: actions/cache@v3
      with:
        path: ${{ steps.composer-cache.outputs.dir }}
        key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
        restore-keys: ${{ runner.os }}-composer-

    - name: Install Composer dependencies
      run: composer install --no-dev --prefer-dist

    - name: Run PHPUnit tests
      run: vendor/bin/phpunit --configuration phpunit.xml

    - name: Run PHPStan (Static Analysis)
      run: vendor/bin/phpstan analyse src --level max

    - name: Build Docker Image
      run: docker build -t your-docker-registry/your-app:${{ github.sha }} .

    - name: Push Docker Image to Registry (e.g., Docker Hub)
      if: github.ref == 'refs/heads/main' # main ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œ๋  ๋•Œ๋งŒ ์‹คํ–‰
      run: |
        echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
        docker push your-docker-registry/your-app:${{ github.sha }}

  deploy:
    needs: build_test # build_test Job์ด ์„ฑ๊ณตํ•ด์•ผ ์‹คํ–‰
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' # main ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œ๋  ๋•Œ๋งŒ ์‹คํ–‰

    steps:
    - name: Deploy to Production Server via SSH
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.SSH_HOST }}
        username: ${{ secrets.SSH_USERNAME }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        script: |
          # ์„œ๋ฒ„์— ์ ‘์†ํ•˜์—ฌ ์ตœ์‹  Docker ์ด๋ฏธ์ง€ pull ๋ฐ ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹œ์ž‘
          docker pull your-docker-registry/your-app:${{ github.sha }}
          docker stop your-app-container || true
          docker rm your-app-container || true
          docker run -d --name your-app-container -p 80:80 your-docker-registry/your-app:${{ github.sha }}
          # ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋“ฑ ์‹คํ–‰
          # docker exec your-app-container php artisan migrate --force


๐Ÿ’ก GitHub Actions Secret ๊ด€๋ฆฌ


์œ„ ์˜ˆ์‹œ์—์„œ secrets.DOCKER_PASSWORD, secrets.DOCKER_USERNAME, secrets.SSH_HOST ๋“ฑ์€ GitHub ์ €์žฅ์†Œ์˜ Settings -> Secrets -> Actions์—์„œ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ๋ฏผ๊ฐํ•œ ์ •๋ณด๋“ค์ž…๋‹ˆ๋‹ค. ์ ˆ๋Œ€๋กœ ์ฝ”๋“œ์— ์ง์ ‘ ๋…ธ์ถœํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.



๊ฒฐ๋ก 



์ด๋กœ์จ ์šฐ๋ฆฌ๋Š” #PHP์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ ์œ„ํ•œ #CI/CDํŒŒ์ดํ”„๋ผ์ธ ์˜ ์„ค๊ณ„๋ถ€ํ„ฐ GitHub Actions๋ฅผ ํ™œ์šฉํ•œ ๊ตฌํ˜„๊นŒ์ง€ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด ํŒŒ์ดํ”„๋ผ์ธ์€ ์ฝ”๋“œ๊ฐ€ ํ‘ธ์‹œ๋˜๋Š” ์ˆœ๊ฐ„๋ถ€ํ„ฐ ๋นŒ๋“œ, ํ…Œ์ŠคํŠธ, ๋ฐฐํฌ์— ์ด๋ฅด๋Š” ๋ชจ๋“  ๊ณผ์ •์„ ์ž๋™ํ™”ํ•˜์—ฌ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•˜๊ณ  ์„œ๋น„์Šค์˜ ์•ˆ์ •์„ฑ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ๊ฐœ๋ฐœ์ž๋Š” ๋”์šฑ ๋น ๋ฅด๊ฒŒ ํ˜์‹ ํ•˜๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ ๋” ๋‚˜์€ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



๋ฌด๋ฃŒ์ฒดํ—˜, ๋Š๊น€์—†์ด ๋น ๋ฅธVPN VPN, ๊ตญ๋‚ด ๋‹ค๋Ÿ‰IP, ๋ชจ๋ฐ”์ผ๊ฐ€๋Šฅ, ๋ณธ์‚ฌ ํ’ˆ์งˆ๊ด€๋ฆฌ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ณด์•ˆ์„ฑ ๋†’์€ VPN ์„œ๋น„์Šค

https://xn--299ao67b9qbmsf04c.net/