웹사이트 검색

Ubuntu 16.04에서 Kubernetes로 PHP 애플리케이션을 배포하는 방법


저자는 Write for DOnations 프로그램을 선택했습니다.

소개

Kubernetes는 오픈 소스 컨테이너 오케스트레이션 시스템입니다. 다운타임에 대한 걱정 없이 컨테이너를 생성, 업데이트 및 확장할 수 있습니다.

PHP 애플리케이션을 실행하기 위해 Nginx는 PHP-FPM에 대한 프록시 역할을 합니다. 단일 컨테이너에서 이 설정을 컨테이너화하는 것은 번거로운 프로세스일 수 있지만 Kubernetes는 두 서비스를 별도의 컨테이너에서 관리하는 데 도움이 됩니다. Kubernetes를 사용하면 컨테이너를 재사용 및 교체 가능하게 유지할 수 있으며 새 버전의 Nginx 또는 PHP가 있을 때마다 컨테이너 이미지를 다시 빌드할 필요가 없습니다.

이 자습서에서는 Nginx 및 PHP-FPM이 별도의 컨테이너에서 실행되는 Kubernetes 클러스터에 PHP 7 애플리케이션을 배포합니다. 또한 DigitalOcean의 블록 스토리지 시스템을 사용하여 구성 파일과 애플리케이션 코드를 컨테이너 이미지 외부에 유지하는 방법도 배우게 됩니다. 이 접근 방식을 사용하면 이미지를 다시 빌드하는 대신 구성 볼륨을 전달하여 웹/프록시 서버가 필요한 모든 애플리케이션에 Nginx 이미지를 재사용할 수 있습니다.

참고: 이 튜토리얼은 최신 정보 및 튜토리얼을 위해 DigitalOcean Kubernetes 제품 문서로 만든 Kubernetes 클러스터에서 테스트되었습니다.

전제 조건

  • Kubernetes 개체에 대한 기본적인 이해. 자세한 내용은 Kubernetes 소개 문서를 확인하세요.
  • Ubuntu 16.04에서 실행되는 Kubernetes 클러스터. Ubuntu 16.04에서 Kubeadm을 사용하여 Kubernetes 1.10 클러스터를 만드는 방법 자습서에 따라 이를 설정할 수 있습니다.
  • 스토리지 볼륨을 생성하기 위한 읽기 및 쓰기 권한이 있는 DigitalOcean 계정 및 API 액세스 토큰. API 액세스 토큰이 없으면 여기에서 만들 수 있습니다.
  • Github와 같이 공개적으로 액세스할 수 있는 URL에서 호스팅되는 애플리케이션 코드입니다.

1단계 - PHP-FPM 및 Nginx 서비스 생성

이 단계에서는 PHP-FPM 및 Nginx 서비스를 생성합니다. 서비스는 클러스터 내에서 포드 세트에 대한 액세스를 허용합니다. 클러스터 내의 서비스는 IP 주소 없이도 이름을 통해 직접 통신할 수 있습니다. PHP-FPM 서비스는 PHP-FPM 포드에 대한 액세스를 허용하고 Nginx 서비스는 Nginx 포드에 대한 액세스를 허용합니다.

Nginx 팟은 PHP-FPM 팟을 프록시하므로 이를 찾는 방법을 서비스에 알려야 합니다. IP 주소를 사용하는 대신 Kubernetes의 자동 서비스 검색을 활용하여 사람이 읽을 수 있는 이름을 사용하여 요청을 적절한 서비스로 라우팅합니다.

서비스를 만들려면 개체 정의 파일을 만듭니다. 모든 Kubernetes 개체 정의는 최소한 다음 항목을 포함하는 YAML 파일입니다.

  • apiVersion: 정의가 속한 Kubernetes API의 버전입니다.
  • 종류: 이 파일이 나타내는 Kubernetes 개체입니다. 예를 들어 pod 또는 service입니다.
  • 메타데이터: 여기에는 적용하려는 라벨과 함께 개체의 이름이 포함됩니다.
  • spec: 여기에는 컨테이너 이미지 또는 컨테이너에 액세스할 수 있는 포트와 같이 생성하는 개체의 종류에 따라 특정 구성이 포함됩니다.

먼저 Kubernetes 개체 정의를 저장할 디렉터리를 만듭니다.

마스터 노드에 SSH로 연결하고 Kubernetes 개체 정의를 저장할 definitions 디렉터리를 만듭니다.

  1. mkdir definitions

새로 생성된 definitions 디렉토리로 이동합니다.

  1. cd definitions

php_service.yaml 파일을 생성하여 PHP-FPM 서비스를 만듭니다.

  1. nano php_service.yaml

kindService로 설정하여 이 개체가 서비스임을 지정합니다.

...
apiVersion: v1
kind: Service

PHP-FPM에 대한 액세스를 제공하므로 서비스 이름을 php로 지정합니다.

...
metadata:
  name: php

서로 다른 개체를 레이블로 논리적으로 그룹화합니다. 이 자습서에서는 레이블을 사용하여 개체를 프런트엔드 또는 백엔드와 같은 "계층\으로 그룹화합니다. PHP 포드는 이 서비스 뒤에서 실행되므로 계층: 백엔드로 레이블을 지정합니다.

...
  labels:
    tier: backend

서비스는 selector 레이블을 사용하여 액세스할 포드를 결정합니다. 포드가 서비스 이전 또는 이후에 생성되었는지 여부에 관계없이 이러한 레이블과 일치하는 포드가 서비스됩니다. 이 튜토리얼의 뒷부분에서 팟(Pod)에 대한 레이블을 추가합니다.

tier: backend 레이블을 사용하여 포드를 백엔드 계층에 할당합니다. 또한 app: php 레이블을 추가하여 이 포드가 PHP를 실행하도록 지정합니다. metadata 섹션 뒤에 이 두 레이블을 추가합니다.

...
spec:
  selector:
    app: php
    tier: backend

다음으로 이 서비스에 액세스하는 데 사용되는 포트를 지정합니다. 이 자습서에서는 포트 9000을 사용합니다. spec 아래의 php_service.yaml 파일에 추가하십시오.

...
  ports:
    - protocol: TCP
      port: 9000

완료된 php_service.yaml 파일은 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: php
  labels:
    tier: backend
spec:
  selector:
    app: php
    tier: backend
  ports:
  - protocol: TCP
    port: 9000

CTRL + o를 눌러 파일을 저장한 다음 CTRL + x를 눌러 nano를 종료합니다.

이제 서비스에 대한 개체 정의를 만들었으므로 서비스를 실행하려면 -f 인수와 함께 kubectl apply 명령을 사용하고 php_service.yaml 파일.

서비스 만들기:

  1. kubectl apply -f php_service.yaml

이 출력은 서비스 생성을 확인합니다.

Output
service/php created

서비스가 실행 중인지 확인합니다.

  1. kubectl get svc

PHP-FPM 서비스가 실행되는 것을 볼 수 있습니다:

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10m php ClusterIP 10.100.59.238 <none> 9000/TCP 5m

Kubernetes가 지원하는 다양한 서비스 유형이 있습니다. php 서비스는 기본 서비스 유형인 ClusterIP를 사용합니다. 이 서비스 유형은 내부 IP를 할당하고 클러스터 내에서만 서비스에 연결할 수 있도록 합니다.

이제 PHP-FPM 서비스가 준비되었으므로 Nginx 서비스를 생성합니다. 편집기를 사용하여 nginx_service.yaml이라는 새 파일을 만들고 엽니다.

  1. nano nginx_service.yaml

이 서비스는 Nginx 포드를 대상으로 하므로 이름을 nginx로 지정합니다. 백엔드 계층에 속하는 tier: backend 레이블도 추가합니다.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    tier: backend

php 서비스와 유사하게 app: nginxtier: backend 선택기 레이블을 사용하여 포드를 대상으로 지정합니다. 기본 HTTP 포트인 포트 80에서 이 서비스에 액세스할 수 있도록 합니다.

...
spec:
  selector:
    app: nginx
    tier: backend
  ports:
  - protocol: TCP
    port: 80

Nginx 서비스는 Droplet의 공용 IP 주소에서 인터넷에 공개적으로 액세스할 수 있습니다. your_public_ip는 DigitalOcean Cloud Panel에서 찾을 수 있습니다. spec.externalIPs 아래에 다음을 추가합니다.

...
spec:
  externalIPs:
  - your_public_ip

nginx_service.yaml 파일은 다음과 같습니다.

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    tier: backend
spec:
  selector:
    app: nginx
    tier: backend
  ports:
  - protocol: TCP
    port: 80
  externalIPs:
  - your_public_ip    

파일을 저장하고 닫습니다. Nginx 서비스를 생성합니다.

  1. kubectl apply -f nginx_service.yaml

서비스가 실행 중일 때 다음 출력이 표시됩니다.

Output
service/nginx created

다음을 실행하여 실행 중인 모든 서비스를 볼 수 있습니다.

  1. kubectl get svc

출력에 나열된 PHP-FPM 및 Nginx 서비스가 모두 표시됩니다.

Output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13m nginx ClusterIP 10.102.160.47 your_public_ip 80/TCP 50s php ClusterIP 10.100.59.238 <none> 9000/TCP 8m

서비스를 삭제하려면 다음을 실행할 수 있습니다.

  1. kubectl delete svc/service_name

이제 PHP-FPM 및 Nginx 서비스를 생성했으므로 애플리케이션 코드 및 구성 파일을 저장할 위치를 지정해야 합니다.

2단계 - DigitalOcean 스토리지 플러그인 설치

Kubernetes는 환경에 대한 스토리지 공간을 생성할 수 있는 다양한 스토리지 플러그인을 제공합니다. 이 단계에서는 DigitalOcean에 블록 스토리지를 설치합니다. 설치가 완료되면 블록 스토리지를 생성하는 데 사용할 do-block-storage라는 스토리지 클래스가 추가됩니다.

먼저 DigitalOcean API 토큰을 저장할 Kubernetes 시크릿 객체를 구성합니다. 비밀 개체는 SSH 키 및 암호와 같은 민감한 정보를 동일한 네임스페이스 내의 다른 Kubernetes 개체와 공유하는 데 사용됩니다. 네임스페이스는 Kubernetes 객체를 논리적으로 분리하는 방법을 제공합니다.

편집기로 secret.yaml 파일을 엽니다.

  1. nano secret.yaml

비밀 개체의 이름을 digitalocean으로 지정하고 kube-system 네임스페이스에 추가합니다. kube-system 네임스페이스는 Kubernetes 내부 서비스의 기본 네임스페이스이며 DigitalOcean 스토리지 플러그인에서 다양한 구성 요소를 실행하는 데에도 사용됩니다.

apiVersion: v1
kind: Secret
metadata:
  name: digitalocean
  namespace: kube-system

보안 비밀은 spec 키 대신 data 또는 stringData 키를 사용하여 필요한 정보를 보유합니다. data 매개변수는 검색 시 자동으로 디코딩되는 base64 인코딩 데이터를 보유합니다. stringData 매개변수는 생성 또는 업데이트 중에 자동으로 인코딩되는 인코딩되지 않은 데이터를 보유하며 비밀을 검색할 때 데이터를 출력하지 않습니다. 이 자습서에서는 편의를 위해 stringData를 사용합니다.

access-tokenstringData로 추가합니다.

...
stringData:
  access-token: your-api-token

파일을 저장하고 종료합니다.

secret.yaml 파일은 다음과 같습니다.

apiVersion: v1
kind: Secret
metadata:
  name: digitalocean
  namespace: kube-system
stringData:
  access-token: your-api-token

비밀 만들기:

  1. kubectl apply -f secret.yaml

비밀 생성 시 다음 출력이 표시됩니다.

Output
secret/digitalocean created

다음 명령을 사용하여 비밀을 볼 수 있습니다.

  1. kubectl -n kube-system get secret digitalocean

출력은 다음과 유사합니다.

Output
NAME TYPE DATA AGE digitalocean Opaque 1 41s

Opaque 유형은 이 비밀이 stringData 비밀의 표준인 읽기 전용임을 의미합니다. 이에 대한 자세한 내용은 Secret 디자인 사양에서 확인할 수 있습니다. DATA 필드는 이 비밀에 저장된 항목의 수를 보여줍니다. 이 경우 하나의 키가 저장되어 있으므로 1로 표시됩니다.

이제 Secret이 준비되었으므로 DigitalOcean 블록 스토리지 플러그인을 설치합니다.

  1. kubectl apply -f https://raw.githubusercontent.com/digitalocean/csi-digitalocean/master/deploy/kubernetes/releases/csi-digitalocean-v0.3.0.yaml

다음과 유사한 출력이 표시됩니다.

Output
storageclass.storage.k8s.io/do-block-storage created serviceaccount/csi-attacher created clusterrole.rbac.authorization.k8s.io/external-attacher-runner created clusterrolebinding.rbac.authorization.k8s.io/csi-attacher-role created service/csi-attacher-doplug-in created statefulset.apps/csi-attacher-doplug-in created serviceaccount/csi-provisioner created clusterrole.rbac.authorization.k8s.io/external-provisioner-runner created clusterrolebinding.rbac.authorization.k8s.io/csi-provisioner-role created service/csi-provisioner-doplug-in created statefulset.apps/csi-provisioner-doplug-in created serviceaccount/csi-doplug-in created clusterrole.rbac.authorization.k8s.io/csi-doplug-in created clusterrolebinding.rbac.authorization.k8s.io/csi-doplug-in created daemonset.apps/csi-doplug-in created

이제 DigitalOcean 스토리지 플러그인을 설치했으므로 애플리케이션 코드 및 구성 파일을 보관할 블록 스토리지를 생성할 수 있습니다.

3단계 - 영구 볼륨 생성

시크릿이 제자리에 있고 블록 스토리지 플러그인이 설치되었으므로 이제 영구 볼륨을 생성할 준비가 되었습니다. 영구 볼륨(PV)은 포드의 수명 주기와 독립적으로 존재하는 지정된 크기의 블록 스토리지입니다. 영구 볼륨을 사용하면 애플리케이션 코드 손실에 대한 걱정 없이 포드를 관리하거나 업데이트할 수 있습니다. 영구 볼륨은 필요한 경로에 PV를 마운트하는 PersistentVolumeClaim 또는 PVC를 사용하여 액세스합니다.

편집기로 code_volume.yaml 파일을 엽니다.

  1. nano code_volume.yaml

파일에 다음 매개변수와 값을 추가하여 PVC code의 이름을 지정합니다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: code

PVC의 사양에는 다음 항목이 포함됩니다.

  • accessModes는 사용 사례에 따라 다릅니다. 이것들은:
    • ReadWriteOnce – 볼륨을 단일 노드에서 읽기-쓰기로 마운트합니다.
    • ReadOnlyMany – 볼륨을 많은 노드에서 읽기 전용으로 마운트
    • ReadWriteMany – 많은 노드에서 읽기-쓰기로 볼륨을 마운트합니다.

    DigitalOcean 블록 스토리지는 단일 노드에만 마운트되므로 accessModesReadWriteOnce로 설정합니다. 이 튜토리얼은 소량의 애플리케이션 코드를 추가하는 과정을 안내하므로 이 사용 사례에서는 1GB면 충분합니다. 더 많은 양의 코드 또는 데이터를 볼륨에 저장할 계획이라면 요구 사항에 맞게 storage 매개변수를 수정할 수 있습니다. 볼륨 생성 후 스토리지 양을 늘릴 수 있지만 디스크 축소는 지원되지 않습니다.

    ...
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
    

    그런 다음 Kubernetes가 볼륨을 프로비저닝하는 데 사용할 스토리지 클래스를 지정하십시오. DigitalOcean 블록 스토리지 플러그인에서 생성한 do-block-storage 클래스를 사용합니다.

    ...
      storageClassName: do-block-storage
    

    code_volume.yaml 파일은 다음과 같습니다.

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: code
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
      storageClassName: do-block-storage
    

    파일을 저장하고 종료합니다.

    kubectl을 사용하여 code PersistentVolumeClaim을 생성합니다.

    1. kubectl apply -f code_volume.yaml

    다음 출력은 개체가 성공적으로 생성되었으며 1GB PVC를 볼륨으로 탑재할 준비가 되었음을 알려줍니다.

    Output
    persistentvolumeclaim/code created

    사용 가능한 영구 볼륨(PV)을 보려면:

    1. kubectl get pv

    PV 목록이 표시됩니다.

    Output
    NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-ca4df10f-ab8c-11e8-b89d-12331aa95b13 1Gi RWO Delete Bound default/code do-block-storage 2m

    위의 필드는 재확보 정책상태를 제외한 구성 파일의 개요입니다. 회수 정책은 PV에 액세스하는 PVC가 삭제된 후 PV로 수행되는 작업을 정의합니다. Delete는 Kubernetes 및 DigitalOcean 인프라에서 PV를 제거합니다. Kubernetes PV 설명서에서 재확보 정책상태에 대해 자세히 알아볼 수 있습니다.

    DigitalOcean 블록 스토리지 플러그인을 사용하여 영구 볼륨을 성공적으로 생성했습니다. 영구 볼륨이 준비되었으므로 이제 배포를 사용하여 포드를 생성합니다.

    4단계 - PHP-FPM 배포 생성

    이 단계에서는 배포를 사용하여 PHP-FPM 포드를 만드는 방법을 배웁니다. 배포는 ReplicaSet를 사용하여 포드를 생성, 업데이트 및 관리하는 일관된 방법을 제공합니다. 업데이트가 예상대로 작동하지 않으면 배포가 포드를 이전 이미지로 자동 롤백합니다.

    배포 spec.selector 키는 관리할 포드의 레이블을 나열합니다. 또한 template 키를 사용하여 필요한 포드를 생성합니다.

    이 단계에서는 초기화 컨테이너의 사용도 소개합니다. 컨테이너 초기화는 포드의 템플릿 키 아래에 지정된 일반 컨테이너 전에 하나 이상의 명령을 실행합니다. 이 튜토리얼에서 Init Container는 wget을 사용하여 GitHub Gist에서 샘플 index.php 파일을 가져옵니다. 다음은 샘플 파일의 내용입니다.

    <?php
    echo phpinfo(); 
    

    배포를 만들려면 편집기에서 php_deployment.yaml이라는 새 파일을 엽니다.

    1. nano php_deployment.yaml

    이 배포는 PHP-FPM 포드를 관리하므로 배포 개체의 이름을 php로 지정합니다. 포드는 백엔드 계층에 속하므로 tier: backend 레이블을 사용하여 배포를 이 그룹으로 그룹화합니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: php
      labels:
        tier: backend
    

    배포 사양의 경우 replicas 매개변수를 사용하여 생성할 이 포드의 복사본 수를 지정합니다. 복제본의 수는 요구 사항과 사용 가능한 리소스에 따라 달라집니다. 이 자습서에서는 하나의 복제본을 만듭니다.

    ...
    spec:
      replicas: 1
    

    이 배포는 app: phptier: backend 레이블과 일치하는 포드를 관리합니다. 선택기 키 아래에 다음을 추가합니다.

    ...
      selector:
        matchLabels:
          app: php
          tier: backend
    

    다음으로 배포 사양에는 포드의 개체 정의에 대한 템플릿이 필요합니다. 이 템플릿은 포드를 생성할 사양을 정의합니다. 먼저 php 서비스 selectors 및 배포의 matchLabels에 지정된 레이블을 추가합니다. template.metadata.labels 아래에 app: phptier: backend를 추가합니다.

    ...
      template:
        metadata:
          labels:
            app: php
            tier: backend
    

    Pod에는 여러 컨테이너와 볼륨이 있을 수 있지만 각각에는 이름이 필요합니다. 각 볼륨에 대한 탑재 경로를 지정하여 선택적으로 볼륨을 컨테이너에 탑재할 수 있습니다.

    먼저 컨테이너가 액세스할 볼륨을 지정합니다. 애플리케이션 코드를 보관하기 위해 이름이 code인 PVC를 만들었으므로 이 볼륨의 이름도 code로 지정합니다. spec.template.spec.volumes 아래에 다음을 추가합니다.

    ...
        spec:
          volumes:
          - name: code
            persistentVolumeClaim:
              claimName: code
    

    다음으로 이 팟(Pod)에서 실행할 컨테이너를 지정하십시오. Docker 스토어에서 다양한 이미지를 찾을 수 있지만 이 자습서에서는 php:7-fpm 이미지를 사용합니다.

    spec.template.spec.containers 아래에 다음을 추가합니다.

    ...
          containers:
          - name: php
            image: php:7-fpm
    

    다음으로 컨테이너가 액세스해야 하는 볼륨을 마운트합니다. 이 컨테이너는 PHP 코드를 실행하므로 code 볼륨에 액세스해야 합니다. 또한 mountPath를 사용하여 /code를 마운트 지점으로 지정합니다.

    spec.template.spec.containers.volumeMounts 아래에 다음을 추가합니다.

    ...
            volumeMounts:
            - name: code
              mountPath: /code
    

    이제 볼륨을 마운트했으므로 볼륨에서 애플리케이션 코드를 가져와야 합니다. 이전에 FTP/SFTP를 사용했거나 이를 수행하기 위해 SSH 연결을 통해 코드를 복제했을 수 있지만 이 단계에서는 초기화 컨테이너를 사용하여 코드를 복사하는 방법을 보여줍니다.

    설정 프로세스의 복잡성에 따라 단일 initContainer를 사용하여 애플리케이션을 빌드하는 스크립트를 실행하거나 명령당 하나의 initContainer를 사용할 수 있습니다. 볼륨이 initContainer에 마운트되었는지 확인하십시오.

    이 자습서에서는 busybox와 함께 단일 초기화 컨테이너를 사용하여 코드를 다운로드합니다. busybox는 이를 수행하는 데 사용할 wget 유틸리티가 포함된 작은 이미지입니다.

    spec.template.spec에서 initContainer를 추가하고 busybox 이미지를 지정합니다.

    ...
          initContainers:
          - name: install
            image: busybox
    

    Init Container는 해당 위치에서 코드를 다운로드할 수 있도록 code 볼륨에 액세스해야 합니다. spec.template.spec.initContainers에서 볼륨 code/code 경로에 마운트합니다.

    ...
            volumeMounts:
            - name: code
              mountPath: /code
    

    각 초기화 컨테이너는 명령을 실행해야 합니다. Init Container는 wget을 사용하여 Github를 /code 작업 디렉토리에 다운로드합니다. -O 옵션은 다운로드한 파일에 이름을 지정하고 이 파일의 이름을 index.php로 지정합니다.

    참고: 가져오는 코드를 신뢰해야 합니다. 서버로 가져오기 전에 소스 코드를 검사하여 코드가 수행하는 작업에 익숙한지 확인하십시오.

    spec.template.spec.initContainersinstall 컨테이너에서 다음 줄을 추가합니다.

    ...
            command:
            - wget
            - "-O"
            - "/code/index.php"
            - https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php
    

    완료된 php_deployment.yaml 파일은 다음과 같습니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: php
      labels:
        tier: backend
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: php
          tier: backend
      template:
        metadata:
          labels:
            app: php
            tier: backend
        spec:
          volumes:
          - name: code
            persistentVolumeClaim:
              claimName: code
          containers:
          - name: php
            image: php:7-fpm
            volumeMounts:
            - name: code
              mountPath: /code
          initContainers:
          - name: install
            image: busybox
            volumeMounts:
            - name: code
              mountPath: /code
            command:
            - wget
            - "-O"
            - "/code/index.php"
            - https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php
    

    파일을 저장하고 편집기를 종료합니다.

    kubectl을 사용하여 PHP-FPM 배포를 만듭니다.

    1. kubectl apply -f php_deployment.yaml

    배포 생성 시 다음 출력이 표시됩니다.

    Output
    deployment.apps/php created

    요약하면 이 배포는 지정된 이미지를 다운로드하여 시작됩니다. 그런 다음 PersistentVolumeClaim에서 PersistentVolume을 요청하고 initContainers를 순차적으로 실행합니다. 완료되면 컨테이너가 실행되고 지정된 마운트 지점에 볼륨이 마운트됩니다. 이 모든 단계가 완료되면 포드가 실행됩니다.

    다음을 실행하여 배포를 볼 수 있습니다.

    1. kubectl get deployments

    출력이 표시됩니다.

    Output
    NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE php 1 1 1 0 19s

    이 출력은 배포의 현재 상태를 이해하는 데 도움이 될 수 있습니다. 배포는 Kubernetes 배포 문서입니다.

    다음 명령어를 사용하여 이 배포가 시작한 포드를 볼 수 있습니다.

    1. kubectl get pods

    이 명령어의 출력은 배포 생성 이후 경과된 시간에 따라 달라집니다. 생성 직후 실행하면 출력은 다음과 같습니다.

    Output
    NAME READY STATUS RESTARTS AGE php-86d59fd666-bf8zd 0/1 Init:0/1 0 9s

    열은 다음 정보를 나타냅니다.

    • Ready: 이 포드를 실행하는 replicas의 수입니다.
    • 상태: 포드의 상태입니다. 초기화는 초기화 컨테이너가 실행 중임을 나타냅니다. 이 출력에서는 초기화 컨테이너 1개 중 0개가 실행을 완료했습니다.
    • 다시 시작: 포드를 시작하기 위해 이 프로세스가 다시 시작된 횟수입니다. 초기화 컨테이너 중 하나라도 실패하면 이 숫자가 증가합니다. 배포는 원하는 상태에 도달할 때까지 다시 시작합니다.

    시작 스크립트의 복잡성에 따라 상태가 podInitializing으로 변경되는 데 몇 분 정도 걸릴 수 있습니다.

    Output
    NAME READY STATUS RESTARTS AGE php-86d59fd666-lkwgn 0/1 podInitializing 0 39s

    이는 초기화 컨테이너가 완료되었고 컨테이너가 초기화 중임을 의미합니다. 모든 컨테이너가 실행 중일 때 명령을 실행하면 포드 상태가 실행 중으로 변경되는 것을 볼 수 있습니다.

    Output
    NAME READY STATUS RESTARTS AGE php-86d59fd666-lkwgn 1/1 Running 0 1m

    이제 팟(Pod)이 성공적으로 실행되고 있음을 알 수 있습니다. 팟(Pod)이 시작되지 않으면 다음 명령을 사용하여 디버그할 수 있습니다.

    • 포드의 상세 정보 보기:

    1. kubectl describe pods pod-name

    • Pod에서 생성된 로그 보기:

    1. kubectl logs pod-name

    • 포드의 특정 컨테이너에 대한 로그 보기:

    1. kubectl logs pod-name container-name

    애플리케이션 코드가 마운트되었고 이제 PHP-FPM 서비스가 연결을 처리할 준비가 되었습니다. 이제 Nginx 배포를 만들 수 있습니다.

    5단계 - Nginx 배포 생성

    이 단계에서는 ConfigMap을 사용하여 Nginx를 구성합니다. ConfigMap은 다른 Kubernetes 객체 정의에서 참조할 수 있는 키-값 형식으로 구성을 보유합니다. 이 접근 방식은 필요한 경우 이미지를 다른 Nginx 버전으로 재사용하거나 교체할 수 있는 유연성을 제공합니다. ConfigMap을 업데이트하면 변경 사항이 이를 마운트하는 포드에 자동으로 복제됩니다.

    편집기를 사용하여 ConfigMap에 대한 nginx_configMap.yaml 파일을 만듭니다.

    1. nano nginx_configMap.yaml

    ConfigMap nginx-config의 이름을 지정하고 tier: backend 마이크로 서비스로 그룹화합니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-config
      labels:
        tier: backend
    

    다음으로 ConfigMap에 대한 데이터를 추가합니다. 키 이름을 config로 지정하고 Nginx 구성 파일의 내용을 값으로 추가합니다. 이 자습서의 예제 Nginx 구성을 사용할 수 있습니다.

    Kubernetes는 요청을 서비스에 대한 적절한 호스트로 라우팅할 수 있으므로 IP 주소 대신 fastcgi_pass 매개변수에 PHP-FPM 서비스의 이름을 입력할 수 있습니다. nginx_configMap.yaml 파일에 다음을 추가합니다.

    ...
    data:
      config : |
        server {
          index index.php index.html;
          error_log  /var/log/nginx/error.log;
          access_log /var/log/nginx/access.log;
          root ^/code^;
    
          location / {
              try_files $uri $uri/ /index.php?$query_string;
          }
    
          location ~ \.php$ {
              try_files $uri =404;
              fastcgi_split_path_info ^(.+\.php)(/.+)$;
              fastcgi_pass php:9000;
              fastcgi_index index.php;
              include fastcgi_params;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
              fastcgi_param PATH_INFO $fastcgi_path_info;
            }
        }
    

    nginx_configMap.yaml 파일은 다음과 같습니다.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-config
      labels:
        tier: backend
    data:
      config : |
        server {
          index index.php index.html;
          error_log  /var/log/nginx/error.log;
          access_log /var/log/nginx/access.log;
          root /code;
          
          location / {
              try_files $uri $uri/ /index.php?$query_string;
          }
    
          location ~ \.php$ {
              try_files $uri =404;
              fastcgi_split_path_info ^(.+\.php)(/.+)$;
              fastcgi_pass php:9000;
              fastcgi_index index.php;
              include fastcgi_params;
              fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
              fastcgi_param PATH_INFO $fastcgi_path_info;
            }
        }
    

    파일을 저장하고 편집기를 종료합니다.

    ConfigMap을 생성합니다.

    1. kubectl apply -f nginx_configMap.yaml

    다음 출력이 표시됩니다.

    Output
    configmap/nginx-config created

    ConfigMap 생성을 완료했으며 이제 Nginx 배포를 빌드할 수 있습니다.

    편집기에서 새 nginx_deployment.yaml 파일을 열어 시작합니다.

    1. nano nginx_deployment.yaml

    배포 이름을 nginx로 지정하고 tier: backend 레이블을 추가합니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      labels:
        tier: backend
    

    배포 사양에서 하나의 복제본을 원한다고 지정합니다. 이 배포는 app: nginxtier: backend 레이블이 있는 포드를 관리합니다. 다음 매개변수 및 값을 추가합니다.

    ...
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
          tier: backend
    

    다음으로 포드 템플릿을 추가합니다. 배포 selector.matchLabels에 대해 추가한 것과 동일한 레이블을 사용해야 합니다. 다음을 추가합니다.

    ...
      template:
        metadata:
          labels:
            app: nginx
            tier: backend
    

    이전에 생성한 code PVC에 Nginx 액세스 권한을 부여합니다. spec.template.spec.volumes 아래에 다음을 추가합니다.

    ...
        spec:
          volumes:
          - name: code
            persistentVolumeClaim:
              claimName: code
    

    포드는 ConfigMap을 볼륨으로 마운트할 수 있습니다. 파일 이름과 키를 지정하면 해당 값을 내용으로 하는 파일이 생성됩니다. ConfigMap을 사용하려면 경로의 내용을 담을 파일의 이름으로 설정하십시오. config 키에서 site.conf 파일을 생성하려고 합니다. spec.template.spec.volumes 아래에 다음을 추가합니다.

    ...
          - name: config
            configMap:
              name: nginx-config
              items:
              - key: config
                path: site.conf
    

    경고: 파일을 지정하지 않으면 key의 내용이 볼륨의 mountPath를 대체합니다. 즉, 경로를 명시적으로 지정하지 않으면 대상 폴더의 모든 콘텐츠가 손실됩니다.

    다음으로 포드를 만들 이미지를 지정합니다. 이 튜토리얼에서는 안정성을 위해 nginx:1.7.9 이미지를 사용하지만 Docker 스토어에서 다른 Nginx 이미지를 찾을 수 있습니다. 또한 포트 80에서 Nginx를 사용할 수 있도록 합니다. spec.template.spec 아래에 다음을 추가합니다.

    ...
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - containerPort: 80
    

    Nginx와 PHP-FPM은 동일한 경로에서 파일에 액세스해야 하므로 code 볼륨을 /code에 마운트합니다.

    ...
            volumeMounts:
            - name: code
              mountPath: /code
    

    nginx:1.7.9 이미지는 /etc/nginx/conf.d 디렉토리 아래의 모든 구성 파일을 자동으로 로드합니다. 이 디렉터리에 config 볼륨을 마운트하면 /etc/nginx/conf.d/site.conf 파일이 생성됩니다. volumeMounts 아래에 다음을 추가합니다.

    ...
            - name: config
              mountPath: /etc/nginx/conf.d
    

    nginx_deployment.yaml 파일은 다음과 같습니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      labels:
        tier: backend
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
          tier: backend
      template:
        metadata:
          labels:
            app: nginx
            tier: backend
        spec:
          volumes:
          - name: code
            persistentVolumeClaim:
              claimName: code
          - name: config
            configMap:
              name: nginx-config
              items:
              - key: config
                path: site.conf
          containers:
          - name: nginx
            image: nginx:1.7.9
            ports:
            - containerPort: 80
            volumeMounts:
            - name: code
              mountPath: /code
            - name: config
              mountPath: /etc/nginx/conf.d
    

    파일을 저장하고 편집기를 종료합니다.

    Nginx 배포 만들기:

    1. kubectl apply -f nginx_deployment.yaml

    다음 출력은 이제 배포가 생성되었음을 나타냅니다.

    Output
    deployment.apps/nginx created

    다음 명령어를 사용하여 배포를 나열합니다.

    1. kubectl get deployments

    Nginx 및 PHP-FPM 배포가 표시됩니다.

    Output
    NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx 1 1 1 0 16s php 1 1 1 1 7m

    두 배포에서 관리하는 포드를 나열합니다.

    1. kubectl get pods

    실행 중인 포드가 표시됩니다.

    Output
    NAME READY STATUS RESTARTS AGE nginx-7bf5476b6f-zppml 1/1 Running 0 32s php-86d59fd666-lkwgn 1/1 Running 0 7m

    이제 모든 Kubernetes 개체가 활성화되었으므로 브라우저에서 Nginx 서비스를 방문할 수 있습니다.

    실행 중인 서비스를 나열합니다.

    1. kubectl get services -o wide

    Nginx 서비스에 대한 외부 IP를 가져옵니다.

    Output
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 39m <none> nginx ClusterIP 10.102.160.47 your_public_ip 80/TCP 27m app=nginx,tier=backend php ClusterIP 10.100.59.238 <none> 9000/TCP 34m app=php,tier=backend

    브라우저에서 http://your_public_ip를 입력하여 서버를 방문하십시오. php_info()의 출력이 표시되고 Kubernetes 서비스가 실행 중임을 확인할 수 있습니다.

    결론

    이 가이드에서는 PHP-FPM 및 Nginx 서비스를 컨테이너화하여 독립적으로 관리할 수 있도록 했습니다. 이 접근 방식은 성장에 따라 프로젝트의 확장성을 향상시킬 뿐만 아니라 리소스를 효율적으로 사용할 수 있게 해줍니다. 또한 나중에 서비스를 쉽게 업데이트할 수 있도록 애플리케이션 코드를 볼륨에 저장했습니다.