Kubernetes (k8s로도 알려짐)는 오픈 소스 오케스트레이션 시스템입니다. 이를 통해 사용자는 가동 중지 시간을 최소화하면서 컨테이너화된 애플리케이션을 배포, 확장 및 관리할 수 있습니다. 이 튜토리얼에서는 PHP 애플리케이션을 Kubernetes 클러스터에 배포하는 방법을 배웁니다.
Nginx는 PHP-FPM에 대한 프록시 역할을 수행하며 PHP 애플리케이션을 실행합니다. 단일 컨테이너에서 이 두 서비스를 관리하는 것은 어려운 과정입니다. Kubernetes는 이 두 서비스를 서로 다른 두 개의 컨테이너에서 관리할 수 있도록 도와주며 번거로움을 줄여줍니다. 또한 사용자가 컨테이너를 재사용할 수 있게 하여 PHP/Nginx의 새로운 버전이 나올 때마다 컨테이너 이미지를 빌드하는 걱정을 덜어줍니다.
애플리케이션과 프록시 서비스를 두 개의 별도 컨테이너에서 실행하게 됩니다. 이 튜토리얼에서는 로컬 스토리지를 사용하여 Persistent Volume (PV) 및 Persistent Volume Claim (PVC)을 생성하는 방법에 대한 통찰력도 제공합니다. 그런 다음 이 PVC를 사용하여 구성 파일과 코드를 컨테이너 이미지 외부에 보관합니다. 이 튜토리얼을 마치면 프록시 서버가 필요한 다른 애플리케이션에 Nginx 이미지를 재사용할 수 있게 됩니다. 이미지를 다시 빌드하는 대신 구성을 전달함으로써 이를 달성할 수 있습니다.
전제 조건
- Kubernetes(k8s) 및 해당 오브젝트에 대한 기본적인 이해. 다음 가이드에서 Kubernetes 생태계에 대한 자세한 개요.
- Ubuntu 18.04에서 실행 중인 Kubernetes 클러스터. 이 튜토리얼을 따라 kubeadm을 사용하여 Kubernetes 클러스터 생성.
- 또한, 애플리케이션 코드를 공개 URL(예: GitHub.
1단계: PHP-FPM 및 Nginx 서비스 생성
이 단계에서는 PHP-FPM 및 Nginx 서비스를 생성합니다. 모든 서비스는 클러스터 내의 일련의 파드(pod)에 대한 액세스를 제공합니다. 클러스터에 존재하는 모든 서비스는 IP 주소 없이 이름으로 서로 통신할 수 있습니다. PHP-FPM 서비스와 Nginx 서비스는 각각 PHP-FPM 및 Nginx 파드에 대한 액세스를 제공합니다.
Nginx 파드가 PHP-FPM 파드의 프록시 역할을 하므로, PHP-FPM 서비스에 Nginx 파드를 찾는 방법을 알려주어야 합니다. 이를 위해 Kubernetes’의 자동 서비스 검색을 활용하고 사람이 읽을 수 있는 이름을 사용하여 해당 서비스로 요청을 라우팅합니다.
서비스를 생성하려면 다음을 포함하는 YAML 파일을 생성해야 합니다. 이 YAML 파일에는 최소한 다음과 같은 태그가 포함됩니다.
apiVersion: 정의가 속한 Kubernetes API 버전입니다.kind: 이 YAML 파일이 생성하는 Kubernetes 오브젝트의 종류입니다. 예:service,job또는pod.metadata: 오브젝트의 이름과 사용자가 이 오브젝트에 적용하고자 하는 다양한labels이 이 태그 아래에 정의됩니다.spec: 이 태그에는 환경 변수(ENV), 사용할 컨테이너 이미지, 컨테이너 서비스에 액세스할 수 있는 포트 등 오브젝트의 사양이 포함됩니다.
PHP-FPM 서비스 생성
시작하려면 Kubernetes 오브젝트 정의를 보관할 디렉터리를 생성해야 합니다. 마스터 노드에 로그인하고 “definitions:”
|
1 |
mkdir definitions |
definitions 디렉터리로 이동합니다:
|
1 |
cd definitions |
다음으로, PHP-FPM 서비스 파일을 php_service.yaml 파일로 생성합니다:
|
1 |
nano php_fpm_service.yaml |
그 후, apiVersion 및 kind를 php_fpm_service.yaml 파일에 설정합니다:
|
1 2 |
apiVersion: v1 kind: Service |
서비스 이름을 php 또는 php-fpm(으)로 지정합니다. 이는 PHP-FPM 애플리케이션에 대한 액세스를 제공합니다:
|
1 2 3 |
… Metadata: name: php |
php 서비스의 레이블을 tier: backend(으)로 지정합니다. PHP 애플리케이션이 이 서비스 뒤에서 실행되기 때문입니다:
|
1 2 3 |
… labels: tier: backend |
서비스는 selector 레이블을 사용하여 액세스할 파드를 결정합니다. 파드가 생성된 시기에 관계없이 이 레이블과 일치하는 모든 파드가 서비스를 받게 됩니다. 이 튜토리얼의 뒷부분에서 파드에 레이블을 추가하는 방법을 배우게 됩니다.
다음 라벨을 포함합니다: tier: backend 라벨은 파드를 백엔드 티어에 할당하며, 이와 함께 app: php-fpm 라벨은 파드가 PHP-FPM 애플리케이션을 실행함을 나타냅니다. 이 라벨들은 다음 섹션 뒤에 추가해야 합니다: metadata 섹션:
|
1 2 3 4 5 |
… spec: selector: app: php-fpm tier: backend |
다음으로, 이 php-fpm 서비스에 액세스하기 위한 포트를 spec 아래에 선언해야 합니다. 원하는 포트를 추가할 수 있지만, 이 튜토리얼에서는 9000 포트를 사용합니다:
|
1 2 3 4 |
... ports: - protocol: TCP port: 9000 |
위 단계를 완료하면 php_fpm_service.yaml 파일은 다음과 같이 보일 것입니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
apiVersion: v1 kind: Service metadata: name: php labels: tier: backend spec: selector: app: php tier: backend ports: - protocol: TCP port: 9000 |
Enter Ctrl + O를 입력하여 파일을 저장한 다음, Ctrl + X를 입력하여 nano를 종료합니다..
kubectl 명령을 적용하여 PHP 서비스 생성하기
서비스에 대한 오브젝트 정의가 생성되었으므로, kubectl apply 명령을 -f 인자와 함께 php_fpm_service.yaml 파일을 지정하여 실행합니다:
|
1 |
kubectl apply -f php_fpm_service.yaml |
위 명령의 출력은 다음과 같아야 합니다:
|
1 |
service/php created |
다음 명령을 실행하여 php-fpm 서비스가 실행 중인지 확인합니다:
|
1 |
$ kubectl get svc |
php-fpm 서비스가 가동되어 실행 중인 것을 확인할 수 있습니다:
|
1 2 3 |
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 |
Nginx 서비스 생성하기
이제 PHP-FPM 서비스가 준비되었으므로, Nginx 서비스도 생성할 차례입니다. 에디터에서 이 서비스를 위한 새로운 YAML 파일인 nginx_service.yaml 파일을 생성하고 엽니다:
|
1 |
$ nano nginx_service.yaml |
이 서비스의 이름을 nginx로 지정합니다. 이 서비스는 Nginx 파드를 대상으로 합니다. 이 서비스도 백엔드에 속하므로 tier: backend 라벨을 추가해야 합니다:
|
1 2 3 4 5 6 |
apiVersion: v1 kind: Service metadata: name: nginx labels: tier: backend |
php-fpm 서비스에서 했던 것처럼, 파드를 대상으로 지정하기 위해 셀렉터 라벨 app: nginx 및 tier: backend를 추가합니다. 기본 HTTP 포트인 80 포트를 추가하여 이 서비스에 액세스합니다:
|
1 2 3 4 5 6 7 8 |
... spec: selector: app: nginx tier: backend ports: - protocol: TCP port: 80 |
Nginx 서비스는 공인 IP 주소를 통해 인터넷에서 공개적으로 액세스할 수 있습니다. 워커 노드의 IP를 your_public_ip로 추가할 수 있습니다. 다음 라인을 spec.externalIPs: 아래에 추가합니다.
|
1 2 3 4 5 |
... spec: externalIPs: - your_public_ip |
위의 모든 단계를 완료하면 nginx_service.yaml 파일은 다음과 같이 보일 것입니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 |
위의 필수 매개변수를 모두 추가한 후 파일을 저장하고 닫습니다.
kubectl 명령을 적용하여 Nginx 서비스 생성하기
|
1 |
kubectl apply -f nginx_service.yaml |
|
1 |
service/nginx created |
|
1 |
$ kubectl get svc |
|
1 2 3 4 |
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 |
2단계: 로컬 스토리지 및 영구 볼륨(Persistent Volume) 생성
Kubernetes는 환경에 맞는 스토리지 공간을 생성하는 데 도움이 되는 다양한 스토리지 플러그인을 제공합니다. 이 단계에서는 로컬 StorageClass를 생성하는 방법과 이 Storage Class를 사용하여 영구 볼륨(Persistent Volume)을 생성하는 방법을 안내합니다.
로컬 스토리지 생성
에디터에서 다음과 같이 storageClass.yaml 파일을 생성합니다:
|
1 |
$nano storageClass.yaml |
다음과 같이 kind를 "storageClass"로, apiVersion을 "storage.k8s.io/v1"로 추가합니다:
|
1 2 |
kind: StorageClass apiVersion: storage.k8s.io/v1 |
이 StorageClass의 이름을 "my-local-storage"로 지정하고 다음과 같이 provisioner 및 volumeBindingMode를 추가합니다:
|
1 2 3 4 5 |
… metadata: name: my-local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: Immediate |
파일을 저장하고 종료하면 최종 storageClass.yaml 파일은 다음과 같아야 합니다:
|
1 2 3 4 5 6 |
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: my-local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer |
이제 아래와 같이 kubectl create 명령을 실행하여 StorageClass를 생성합니다:
|
1 |
$ kubectl create -f storageClass.yaml |
위 명령을 실행하면 아래와 같은 출력이 표시되어야 합니다:
|
1 |
storageclass.storage.k8s.io/my-local-storage created |
로컬 영구 볼륨(Persistent Volume) 생성
로컬 스토리지를 생성한 후, 로컬 영구 볼륨(Persistent Volume)을 생성할 수 있습니다. PV라고도 하는 영구 볼륨은 파드(pod)의 수명 주기와 독립적인 지정된 크기의 블록 스토리지입니다. 로컬 영구 볼륨은 Kubernetes 클러스터 노드에서 사용할 수 있는 로컬 디스크 또는 디렉터리에 불과합니다. 이 로컬 영구 볼륨을 사용하면 사용자가 로컬 영구 볼륨 클레임(Persistent Volume Claim)을 사용하여 매우 간단하면서도 이식성 있는 방식으로 로컬 스토리지에 액세스할 수 있습니다. 방금 생성한 이 스토리지 클래스를 사용하여 이 로컬 영구 볼륨을 생성할 수 있습니다. 에디터에서 다음과 같이 persistentVolume.yaml 파일을 엽니다:
|
1 |
$ nano persistentVolume.yaml |
이 영구 볼륨의 이름을 다음과 같이 "my-local-pv":
|
1 2 3 4 |
apiVersion: v1 kind: PersistentVolume metadata: name: my-local-pv |
로컬 영구 볼륨을 생성할 때 사용량에 따라 스토리지 용량을 추가할 수 있습니다. 이 튜토리얼에서는 스토리지로 5 Gi를 사용합니다:
|
1 2 3 4 |
… spec: capacity: storage: 5Gi |
accessModes, persistentVolumeReclaimPolicy를 추가하고, storageClass.yaml에서 사용한 것과 동일한 storageClassName을 제공합니다:
|
1 2 3 4 5 |
… accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: my-local-storage |
다음과 같이 Persistent Volume에 대한 local.path를 추가합니다:
|
1 2 3 |
… local: path: /mnt/disk/vol |
필요한 필드를 모두 추가한 후, persistentVolume.yaml 파일은 다음과 같아야 합니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
apiVersion: v1 kind: PersistentVolume metadata: name: my-local-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: my-local-storage local: path: /mnt/disk/vol nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - worker |
로컬 볼륨 준비하기
이제 persistentVolume.yaml 파일에 추가한 대로 “worker” 노드에 로컬 볼륨을 준비해야 합니다. persistentVolume에 구성한 노드에서 아래 명령을 실행하세요. 이 경우에는 “worker” 노드입니다:
|
1 2 3 |
$ DIRNAME="vol" $ mkdir -p /mnt/disk/$DIRNAME $ chmod 777 /mnt/disk/$DIRNAME |
아래 명령을 persistentVolume.yaml 파일이 있는 마스터 노드에서 실행하세요:
|
1 |
kubectl create -f persistentVolume.yaml |
다음과 같은 출력이 표시되어야 합니다:
|
1 |
persistentvolume/my-local-pv created |
로컬 스토리지와 Persistent Volume을 성공적으로 생성했으므로, 이제 애플리케이션 코드와 구성 파일을 저장할 Persistent Volume Claim을 생성할 수 있습니다.
3단계: Persistent Volume 생성
포드를 관리하거나 업데이트하는 동안 애플리케이션 코드를 안전하게 보관해야 합니다. 이를 위해 이전 단계에서 생성한 Persistent Volume을 사용하며, 이는 PersistentVolumeClaim(또는 PVC)을 사용하여 액세스합니다. 이 PVC는 필요한 경로에 PV를 마운트합니다.
다음과 같이 code_volume.yaml 파일을 편집기에서 엽니다:
|
1 |
$ nano code_volume.yaml |
파일에 아래 매개변수와 값을 추가하여 PVC 이름을 code로 지정합니다:
|
1 2 3 4 |
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: code |
PVC의 spec 섹션에는 다음과 같은 항목이 있습니다:
- accessModes: 이 필드에 사용할 수 있는 다양한 값은 다음과 같습니다:
- ReadWriteOnce – 단일 노드에 대해 읽기 및 쓰기 권한을 모두 가진 볼륨을 마운트합니다.
- ReadOnlyMany – 여러 노드에 대해 읽기 전용 권한을 가진 볼륨을 마운트합니다.
- ReadWriteMany – 여러 노드에 대해 읽기 및 쓰기 권한을 모두 가진 볼륨을 마운트합니다.
- resources: 필요한 스토리지 공간을 정의합니다.
로컬 스토리지는 단일 노드에만 마운트되므로 accessMode를 ReadWriteOnce로 설정해야 합니다. 이 튜토리얼에서는 소량의 애플리케이션 코드만 추가하므로 1GB의 스토리지로도 충분합니다. 그러나 더 많은 양의 데이터나 코드를 저장하려면 요구 사항에 따라 storage 매개변수를 수정할 수 있습니다. 볼륨이 생성되면 스토리지 크기를 늘릴 수는 있지만, 줄이는 것은 지원되지 않습니다:
|
1 2 3 4 5 6 7 |
... spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi |
이제 쿠버네티스 클러스터가 볼륨에 할당하는 데 사용할 스토리지 클래스를 선언합니다. 이전 단계에서 생성한 my-local-storage 스토리지 클래스를 여기 storageClassName에 사용하세요:
|
1 2 |
... storageClassName: my-local-storage |
위 단계를 완료하면 code_volume.yaml 파일은 다음과 같아야 합니다:
|
1 2 3 4 5 6 7 8 9 10 11 |
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: code spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: my-local-storage |
이제 파일을 저장하고 종료합니다.
PVC 생성하기
kubectl apply 명령을 실행하여 code PVC를 생성합니다:
|
1 |
$ kubectl apply -f code_volume.yaml |
객체가 성공적으로 생성되었으며 1GB PVC를 볼륨으로 마운트할 준비가 되었음을 나타내는 다음과 같은 출력이 표시되어야 합니다:
|
1 |
persistentvolumeclaim/code created |
다음 명령을 실행하여 사용 가능한 영구 볼륨(PV)을 확인할 수 있습니다:
|
1 |
$ kubectl get pv |
위 명령의 출력은 다음과 같아야 합니다:
|
1 2 |
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 |
반환 정책(Reclaim Policy)과 상태(Status)를 제외한 위의 모든 필드는 구성 파일의 개요입니다. 반환 정책은 해당 PV에 액세스하는 PVC가 삭제된 후 PV에 발생하는 작업을 정의합니다. Delete 값은 쿠버네티스 클러스터와 스토리지 인프라 모두에서 PV를 제거합니다. 쿠버네티스 PV 문서를 참조하여 반환 정책과 상태를 명확히 이해할 수 있습니다.
로컬 스토리지를 사용하여 영구 볼륨을 성공적으로 생성했으므로 이제 디플로이먼트(Deployment)를 사용하여 파드를 생성할 수 있습니다.
4단계: PHP-FPM 애플리케이션을 위한 디플로이먼트 생성
이 단계에서는 디플로이먼트(Deployment)를 사용하여 PHP-FPM 파드를 생성하는 방법을 알아봅니다. 디플로이먼트는 레플리카셋(ReplicaSets)을 사용하여 파드를 생성, 업데이트 및 관리하는 안정적인 방법을 제공합니다. 디플로이먼트는 파드를 이전 이미지로 자동으로 롤백합니다.
디플로이먼트의 spec.selector 키는 디플로이먼트가 관리하는 파드의 모든 레이블을 나열합니다. 또한 template 키를 사용하여 필요한 파드를 생성합니다.
이 단계에서는 초기화 컨테이너(Init Containers)의 적용 방법도 소개합니다. 초기화 컨테이너는 파드의 템플릿 아래에 지정된 일반 컨테이너보다 먼저 몇 가지 명령을 실행합니다. 여기서 초기화 컨테이너는 GitHub Gist(https://gist.github.com/)를 사용하여 샘플 index.php 파일을 가져옵니다. 샘플 파일의 내용은 다음과 같습니다:
|
1 2 |
<?php echo phpinfo(); |
PHP 디플로이먼트 생성하기
에디터에서 php_deployment.yaml 파일을 새로 열어 디플로이먼트를 생성합니다:
|
1 |
$ nano php_deployment.yaml |
이제 이 Deployment가 PHP-FPM 파드를 관리하므로 Deployment 객체 이름을 PHP로 지정합니다. 다음 레이블을 추가합니다: tier: backend (파드가 백엔드 티어에 속하게 되기 때문입니다):
|
1 2 3 4 5 6 |
apiVersion: apps/v1 kind: Deployment metadata: name: php labels: tier: backend |
replica 매개변수를 사용하여 생성할 이 파드의 복제본 수를 지정합니다. 복제본 수는 요구 사항과 사용 가능한 리소스에 따라 다를 수 있습니다. 이 튜토리얼에서는 파드의 복제본을 하나만 생성합니다:
|
1 2 3 4 |
... spec: replicas: 1 |
Add app: php 및 tier:backend 레이블을 selector 키 아래에 추가하여 이 Deployment가 이 두 레이블과 일치하는 파드를 관리하도록 지정합니다:
|
1 2 3 4 5 |
... selector: matchLabels: app: php tier: backend |
이제 파드’의 객체 정의에는 Deployment spec 아래에 템플릿이 필요합니다. 이 템플릿은 파드를 생성하는 데 필요한 사양을 정의합니다. 먼저 php 서비스 셀렉터 및 Deployment의 matchLabels에 지정된 레이블을 추가합니다. 그런 다음 app:php 및 tier:backend 레이블을 template.metadata.labels 아래에 추가합니다.:
|
1 2 3 4 5 6 7 |
... template: metadata: labels: app: php tier: backend |
먼저 컨테이너가 액세스할 모든 볼륨을 지정해야 합니다. 애플리케이션 코드를 저장하기 위해 code라는 이름의 PVC를 생성했으므로 이 볼륨의 이름을 code로 지정합니다:
|
1 2 3 4 5 6 |
... spec: volumes: - name: code persistentVolumeClaim: claimName: code |
다음으로 파드 내부에서 실행할 이미지와 함께 컨테이너 이름을 지정합니다. Docker 스토어(https://hub.docker.com/explore/)에는 다양한 이미지가 있지만, 이 튜토리얼에서는 php:7-fpm 이미지를 사용합니다:
|
1 2 3 4 |
... containers: - name: php image: php:7-fpm |
이제 컨테이너가 액세스해야 하는 볼륨을 마운트합니다. 이 컨테이너는 php 코드를 실행하므로 이전 단계에서 생성한 code 볼륨에 대한 액세스가 필요합니다. 이 단계에서는 초기화 컨테이너(Init Container)를 사용하여 애플리케이션 코드를 복사하는 방법도 배웁니다.
코드를 다운로드하기 위해, 이 튜토리얼에서는 busybox가 포함된 단일 초기화 컨테이너를 사용하는 방법을 안내합니다. Busybox는 이를 수행하는 데 사용할 wget 유틸리티가 포함된 작은 컨테이너입니다.
먼저, spec.template.spec 아래에 initContainer를 추가하고 busybox 이미지를 지정합니다:
|
1 2 3 4 |
... initContainers: - name: install image: busybox |
그런 다음 code 볼륨에 코드를 다운로드하려면 초기화 컨테이너가 해당 볼륨에 액세스할 수 있어야 합니다. 볼륨 code를 /code 경로에 마운트합니다. 해당 경로는 다음 아래에 위치합니다: spec.template.spec.initContainers:
|
1 2 3 4 |
... volumeMounts: - name: code mountPath: /code |
모든 초기화 컨테이너는 명령을 실행해야 합니다. 이 초기화 컨테이너는 wget을 사용하여 code를 Github로부터 /code 디렉토리로 다운로드합니다. -O 옵션을 전달하여 다운로드한 파일에 이름을 지정할 수 있으며, 이 파일의 이름을 index.php로 지정할 수 있습니다..
또한, 다음 줄을 install 컨테이너 아래에 추가합니다: spec.template.spec.initContainers:
|
1 2 3 4 5 6 |
... command: - wget - "-O" - "/code/index.php" - https://raw.githubusercontent.com/do-community/php-kubernetes/master/index.php |
이 모든 단계를 완료하면, php_deployment.yaml 파일은 다음과 같아야 합니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
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 |
이제 파일을 저장하고 종료할 수 있습니다. 다음으로, 다음을 사용하여 PHP-FPM Deployment를 생성합니다: kubectl apply 명령:
|
1 |
$ kubectl apply -f php_deployment.yaml |
Deployment가 성공적으로 생성되면 다음과 같은 출력이 표시됩니다:
|
1 |
deployment.apps/php created |
이 Deployment는 지정된 이미지를 다운로드하는 것으로 시작하여, PersistentVolume을(를) 다음에서 요청합니다: PersistentVolumeClaim, 그런 다음 initContainers을(를) 실행합니다. 이 단계가 완료되면 컨테이너가 실행되고 볼륨을 지정된 마운트 경로에 마운트합니다. 이 모든 단계를 완료하면 파드가 정상적으로 실행됩니다.
다음 명령을 실행하여 Deployment를 확인할 수 있습니다:
|
1 |
$ kubectl get deployments |
위 명령을 실행하면 다음과 같은 출력이 표시됩니다:
|
1 2 |
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE php 1 1 1 0 19s |
이 출력을 통해 Deployment의 현재 상태를 파악할 수 있습니다. Deployment는 원하는 상태(desired state)를 유지하는 컨트롤러입니다. DESIRED 필드는 php라는 이름의 파드 복제본(replica)이 1개 있음을 지정합니다. CURRENT 필드는 현재 DESIRED 상태의 복제본이 몇 개 실행 중인지 나타냅니다. 정상적인 파드의 경우, 이 값은 DESIRED 상태와 일치해야 합니다. 나머지 필드에 대한 자세한 내용은 Kubernetes Deployments 문서.
그 후, 실행 중인 파드의 상태를 확인하려면 다음 명령을 실행하면 됩니다:
|
1 |
$ kubectl get pods |
이 명령의 출력은 Deployment를 생성한 후 경과한 시간에 따라 다를 수 있습니다. Deployment를 생성한 직후에 실행하면 다음과 유사한 출력이 표시됩니다:
|
1 2 |
NAME READY STATUS RESTARTS AGE php-5d8f6bbf7f-56df2 0/1 Init:0/1 0 9s |
설명:
이 열들은 다음과 같은 정보를 나타냅니다:
- Ready: 이 파드를 실행 중인 현재/원하는 복제본의 수입니다.
- Status: pod의 상태입니다. Init:0/1은 Init 컨테이너가 실행 중이며 1개 중 0개의 Init 컨테이너가 실행을 완료했음을 나타냅니다.
- Restarts: 이 프로세스가 pod를 시작하기 위해 재시작된 횟수를 나타냅니다.
pod의 상태가 podInitializing으로 변경되는 데는 시작 스크립트의 복잡성에 따라 몇 분 정도 걸릴 수 있습니다:
|
1 2 |
NAME READY STATUS RESTARTS AGE php-5d8f6bbf7f-56df2 0/1 podInitializing 0 39s |
이는 Init 컨테이너가 성공적으로 실행되었으며 이제 컨테이너가 초기화 중임을 나타냅니다:
|
1 2 |
NAME READY STATUS RESTARTS AGE php-5d8f6bbf7f-56df2 1/1 Running 0 4m10s |
이제 보시다시피 pod가 정상적으로 실행 중입니다. 하지만 pod가 시작되지 않는 경우, 디버깅 목적으로 아래 명령어를 실행할 수 있습니다:
1. pod의 상세 정보를 보려면:
|
1 |
$ kubectl describe pods pod-name |
2. pod의 로그를 보려면:
|
1 |
$ kubectl logs pod-name |
3. pod 내 특정 컨테이너의 로그를 보려면:
|
1 |
$ kubectl logs pod-name container-name |
축하합니다! 애플리케이션 코드를 성공적으로 마운트했으며 PHP-FPM 서비스가 연결을 처리할 준비가 되었습니다. 마찬가지로 Nginx 디플로이먼트(Deployment)를 생성할 수 있습니다.
5단계: Nginx 디플로이먼트 생성
이 단계에서는 ConfigMap을 사용하여 Nginx를 구성하는 방법을 안내합니다. ConfigMap은 다른 Kubernetes 오브젝트 정의에서 사용할 필요한 모든 구성을 키-값 형식으로 보관합니다. 이 방식을 사용하면 필요에 따라 Nginx 이미지를 다른 버전으로 재사용하거나 교체할 수 있는 유연성을 갖게 됩니다. ConfigMap을 업데이트하면 이 ConfigMap.
을 마운트하는 모든 pod에 해당 변경 사항이 자동으로 복제됩니다. 먼저 에디터에서 nginx_configmap.yaml 파일을 엽니다:
|
1 |
$ nano nginx_configMap.yaml |
이제 이 ConfigMap의 이름을 nginx-config로 지정하고 tier: backend 마이크로서비스에 추가합니다:
|
1 2 3 4 5 6 |
apiVersion: v1 kind: ConfigMap metadata: name: nginx-config labels: tier: backend |
또한 ConfigMap에 데이터를 추가할 수 있습니다. config라는 이름의 키를 추가하고 모든 Nginx 설정 파일 내용을 값으로 추가합니다.
Kubernetes는 서비스의 각 호스트로 요청을 라우팅할 수 있으므로, IP 주소 대신 fastcgi_pass 매개변수 아래에 PHP-FPM 서비스 이름을 입력할 수 있습니다. nginx_configMap.yaml 파일에 다음 코드 줄을 추가합니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
... 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 파일은 다음과 같이 보일 것입니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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; } } |
이제 편집기를 저장하고 종료할 수 있습니다. 이제 kubectl apply 명령을 실행하여 다음을 생성하십시오: ConfigMap:
|
1 |
$ kubectl apply -f nginx_configMap.yaml |
그 후, 화면에 다음과 같은 출력이 표시되어야 합니다:
|
1 |
configmap/nginx-config created |
Nginx Configmap을 성공적으로 생성했습니다. 이제 Nginx Deployment를 생성할 수 있습니다.
Nginx Deployment 생성하기
시작하려면, 다음과 같은 이름의 새 파일을 생성할 수 있습니다: nginx_deployment.yaml (편집기에서):
|
1 |
$ nano nginx_deployment.yaml |
이 Deployment의 이름을 nginx로 지정하고, 다음을 추가합니다: tier: backend 레이블:
|
1 2 3 4 5 6 7 |
apiVersion: apps/v1 kind: Deployment metadata: name: nginx labels: tier: backend |
그 후, Deployment 사양(spec)에 replica 필드를 추가하여 레플리카 수를 지정하고, 다음 레이블을 추가합니다: app: nginx 및 tier: backend 레이블:
|
1 2 3 4 5 6 7 |
... spec: replicas: 1 selector: matchLabels: app: nginx tier: backend |
유사하게, 포드(pod) 템플릿을 추가합니다. Deployment의 selector.matchLabels에 추가했던 것과 동일한 레이블을 추가해야 합니다. 다음을 추가할 수 있습니다:
|
1 2 3 4 5 6 |
... template: metadata: labels: app: nginx tier: backend |
다음 매개변수를 아래에 추가하여 이전에 생성된 code PVC에 Nginx가 액세스할 수 있도록 합니다: spec.template.spec.volumes:
|
1 2 3 4 5 6 |
... spec: volumes: - name: code persistentVolumeClaim: claimName: code |
|
1 2 3 4 5 6 7 |
... - name: config configMap: name: nginx-config items: - key: config path: site.conf |
경고: 파일을 지정하지 않으면 키의 내용이 볼륨의 mountPath를 대체합니다. 즉, 경로를 명시적으로 지정하지 않으면 대상 폴더의 모든 내용이 손실됩니다.
이제 포드에서 사용할 이름, 이미지 및 포트를 지정합니다. 여기서는 다음을 사용합니다: nginx:1.7.9 이미지 및 포트 80. 다음 아래에 추가하십시오: spec.template.spec 섹션:
|
1 2 3 4 5 6 |
... containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 |
또한, /code에 code 볼륨을 마운트합니다. Nginx와 PHP-FPM 모두 동일한 경로에서 파일에 액세스해야 하기 때문입니다:
|
1 2 3 4 |
... volumeMounts: - name: code mountPath: /code |
The nginx-1.7.9 이미지는 /etc/nginx/conf.d 폴더 아래의 모든 설정 파일을 자동으로 로드합니다. 이제 이 디렉터리에 config 볼륨을 마운트하면 /etc/nginx/conf.d/site.conf 파일이 생성됩니다. 다음 내용을 volumeMount 섹션 아래에 추가합니다:
|
1 2 3 |
... - name: config mountPath: /etc/nginx/conf.d |
위의 모든 단계를 완료하면 nginx_deployment.yaml 파일은 다음과 같아야 합니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
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 Deployment를 생성할 수 있습니다:
|
1 |
$ kubectl apply -f nginx_deployment.yaml |
명령이 성공적으로 실행되면 다음과 같은 출력이 표시됩니다:
|
1 |
deployment.apps/nginx created |
다음 명령을 실행하여 모든 Deployment를 나열할 수 있습니다:
|
1 |
$ kubectl get deployments |
이제 Nginx 및 PHP-FPM Deployment가 모두 표시됩니다:
또한, 다음 명령을 실행하여 위에 나열된 두 Deployment 모두에 의해 관리되는 pod를 나열할 수 있습니다:
|
1 |
$ kubectl get pods |
다음과 같이 두 pod가 모두 정상적으로 실행 중인 것을 확인할 수 있습니다:
이 시점에서는 모든 Kubernetes 오브젝트가 활성화되어 있으므로, 이제 브라우저에서 Nginx 서비스에 액세스할 수 있습니다.
다음 명령을 실행하여 서비스를 나열합니다:
|
1 |
$ kubectl get services -o wide |
Nginx 서비스의 External IP를 기록해 두세요:
이제 이 Nginx 서비스의 External IP를 사용하여 브라우저에 http://your_public_ip를 입력하여 서버에 접속할 수 있습니다. php_info()의 출력이 표시되어 Kubernetes 서비스가 정상적으로 실행 중임을 확인할 수 있습니다.
결론
이 튜토리얼에서는 PHP-FPM 및 Nginx 서비스를 독립적으로 관리하기 위해 두 서비스를 컨테이너화했습니다. 이를 통해 프로젝트의 확장성을 향상시킬 뿐만 아니라 리소스를 효율적으로 사용할 수 있습니다. 또한 로컬 스토리지와 Persistent Volume을 생성하여 애플리케이션 코드를 볼륨에 저장하고 향후 서비스를 쉽게 업데이트하는 방법도 배웠습니다. 이를 통해 코드의 유용성과 유지 관리성을 향상시켰습니다.
또한, 다음에서 찾을 수 있는 Docker 및 Kubernetes에 초점을 맞춘 다른 튜토리얼도 확인해 보세요: 저희 블로그:
- Kubernetes 알아보기
- Ubuntu 18.04에서 Kubeadm을 사용하여 Kubernetes 클러스터를 생성하는 방법
- Docker 리소스 정리하기 – 이미지, 컨테이너, 볼륨
- Docker Compose를 사용하여 Laravel, Nginx 및 MySQL 배포하기
- 퍼블릭 클라우드의 Ubuntu에서 Docker를 설치 & 운영하는 방법
즐거운 컴퓨팅 되세요!


댓글
아직 댓글이 없습니다. 첫 번째로 작성해 보세요.