Openshift 4.12.0 PV, PVC (NFS) 를 이용한 Volume 추가

리눅스/OpenShift|2023. 5. 10. 15:05
반응형

한번 가동된 Pod (Container) 에서 데이터 입력, 수정, 삭제 등의 작업 후 중지, 재시작을 하게 되면 그동안 작업한 모든 데이터는 날아갑니다.

때문에 Volume 을 특정 디렉토리로 마운트 하고 사용하면 해당 디렉토리의 파일은 컨테이너가 중지 되어도 데이터가 유지되는데요.

데이터 유지와 용량 증설 목적을 가지는 Volume 을 어떻게 설정하고 사용하는지 예제를 통해 알아보도록 하겠습니다.

 

이 예제는 Deployment 오브젝트를 통해 Python 애플리케이션을 배포하고, Persistent Volume Claim (PVC) 을 사용하여 데이터를 보관하기 위한 Volume 1Gi 를 생성, 컨테이너의 /data 디렉토리에 연결하는 것을 보여주고 있습니다.

 

 

1. 설명

 

본 매뉴얼 하단부에서 소개될 yaml 파일과 옵션에 대한 설명으로 시작하겠습니다.

 

1) PV 와 PVC

PersistentVolume (PV) 은 클러스터 레벨에서 관리되는 볼륨이며 스토리지 저장소라고 생각하면 이해가 쉽습니다. 

PersistentVolume (PV) 과 PersistentVolumeClaim (PVC) 은 1:1 매칭이 가장 일반적인 사용 방식입니다.

즉, 하나의 PV 는 하나의 PVC 와 바인딩됩니다. 이는 PV 가 실제 스토리지 리소스를 나타내고, PVC 가 해당 스토리지 리소스에 대한 요청을 표현하기 때문입니다.
하지만 1:n 매핑도 가능합니다. 즉, 하나의 PV 가 여러 개의 PVC 와 바인딩될 수 있습니다. 이 경우 PVC 는 동일한 PV 의 스토리지를 공유하게 됩니다. 이는 여러 개의 애플리케이션이 동일한 스토리지를 사용해야 하는 경우에 유용할 수 있습니다.

대신 1:n 매핑을 위해서는 다음 사항을 고려해야 합니다.
- PV 와 PVC 의 스토리지 클래스 이름 (storageClassName) 이 일치해야 합니다.
- PV 의 용량은 PVC 들이 요청한 총 용량 이상이어야 합니다.
- PVC 의 액세스 모드 (accessModes) 가 PV 의 액세스 모드와 호환되어야 합니다.

  예를 들어 PV 의 액세스 모드가 ReadWriteOnce 이면, PVC 액세스 모드가 ReadWriteOnce 이여야 합니다.

1:n 매핑은 특정 상황에서 유용할 수 있지만, 주의할 점도 있습니다. 여러 PVC 가 동일한 스토리지를 공유하게 되므로 애플리케이션 간의 스토리지 충돌이 발생할 수 있습니다. 따라서 신중하게 구성해야 합니다.

 

2) accessModes

위에서 말한 액세스 모드 (accessModes) 는 PersistentVolumeClaim (PVC) 에서 지정하는 볼륨의 액세스 모드를 정의합니다. accessModes 필드는 다음과 같은 값을 가질 수 있습니다.

- ReadWriteOnce (RWO) : 단일 노드에서 읽기/쓰기 액세스를 지원
- ReadOnlyMany (ROX) : 여러 노드에서 읽기 전용 액세스를 지원 (동시 마운트 가능)
- ReadWriteMany (RWX) : 여러 노드에서 읽기/쓰기 액세스를 지원 (동시 마운트 가능)

액세스 모드는 PVC 에서 요청한 볼륨을 할당할 때 PersistentVolume (PV) 의 액세스 모드와 일치해야 합니다. PV 의 액세스 모드는 볼륨이 생성될 때 설정되며 PVC 와 일치하지 않는 경우 PVC 는 해당 PV 에 바인딩될 수 없습니다.

 

3) persistentVolumeReclaimPolicy

persistentVolumeReclaimPolicy 는 PV 에서 사용되는 속성입니다. 이 속성은 PV 와 연결된 PVC 가 삭제될 때 PV 에서 어떻게 처리할지를 지정합니다. 사용 가능한 옵션은 아래와 같습니다.

- Retain : PV 데이터를 그대로 보존
- Recycle : PV 데이터를 모두 삭제 후 재사용 
- Delete : 사용 종료시 삭제 

 

4) Volume 유형

PV 에서 구성 가능한 Volume 유형은 여러가지가 있습니다.

볼륨을 로컬 디스크에서 생성할 수 있는 emptyDir 과 hostPath 가 있으며, 전용 스토리지를 이용한 NFS 등의 연결도 가능합니다.

- emptyDir : Pod 내에 존재하는 볼륨입니다.

                    emptyDir 은 Pod 가 생성될 때 생성되며 Pod 의 수명 동안 유지됩니다.

                    (단점) 때문에 Pod 가 삭제되면 emptyDir 에 저장된 모든 데이터가 사라집니다.
                    노드의 로컬 디스크에 생성되며 여러 Pod 들 사이에서 데이터를 공유할 목적으로 사용될 수 있습니다.
- hostPath : 호스트 노드 내에 존재하는 볼륨입니다.

                    hostPath 를 사용하면 Pod 내부의 컨테이너가 호스트 노드의 파일 시스템에 직접 액세스할 수 있습니다.

                    때문에 Pod 가 삭제되어도 볼륨의 데이터는 삭제되지 않습니다.

                    여러 컨테이너가 동일한 hostPath를 공유할 수 있습니다.

                    (단점) Worker node 가 여러개일때, Pod 가 재생성되면 다른 노드에 Pod 가 생성되므로 기존 노드의 볼륨 사용 불가

- PV, PVC : '1)' 에서 소개된 내용과 동일합니다.

                    전용 스토리지를 이용하여 Pod 에 영속성 있는 볼륨을 제공합니다. (Local Disk 또는 외부 Storage 원격 연결 가능)
                    Pod 는 이러한 PV 에 바로 연결하지 않고 PVC 를 통하여 연결됩니다.

 

2. NFS Volume 생성

 

본 예제는 PV, PVC 볼륨 유형으로 작성된 NFS 활용 예제입니다.

 

1) PV 생성

다음은 PersistentVolume (PV) 을 생성하는 yaml 파일입니다.

여기에서는 PV 와 PVC 의 용량을 1:1 매칭으로 구성하였습니다.

# vi pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-example
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  nfs:

    server: 115.68.248.217 # NFS 서버 IP
    path: /data                     # NFS 서버에서 공유하는 디렉토리 경로

 

작성한 yaml 파일을 적용하여 PV 를 생성합니다.

# oc apply -f pv.yaml
persistentvolume/pv-example created

 

생성된 PV 를 확인합니다.

# oc get pv
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-example   1Gi        RWO            Retain           Available           standard                6s

 

2) PVC 생성

PersistentVolumeClaim (PVC) yaml 파일을 작성합니다.

# vi pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-example
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

 

작성한 yaml 파일을 적용하여 PVC 를 생성합니다.

# oc apply -f pvc.yaml

persistentvolumeclaim/pvc-example created

 

생성된 PVC 를 확인합니다.

# oc get pvc
NAME          STATUS    VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-example   Bound     pv-example   1Gi        RWO            standard       12s

 

3) Pod 생성 및 Volume 연결

Pod yaml 를 생성하여 볼륨을 붙일 수 있지만 본 예제에서는 Deployment 를 이용해 Pod 를 생성해 보겠습니다.

# vi deployment_volume.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app-example
  template:
    metadata:
      labels:
        app: app-example
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: app-example
        image: default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/python
        ports:
        - containerPort: 8080
          protocol: TCP
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
          runAsNonRoot: true
        volumeMounts:
        - name: my-pvc-volume
          mountPath: /data_client # 컨테이너 내부의 마운트 위치 (디렉토리는 자동 생성됩니다)
      volumes:
      - name: my-pvc-volume
        persistentVolumeClaim:
          claimName: pvc-example
      imagePullSecrets:
      - name: sysdocu

 

위에서 imagePullSecrets 는 이미지를 Registry 에서 다운로드 하기위해 만든 secret 입니다.

claimName 에는 PVC 이름을 넣고, volumeMounts: name: 은 volumes: name: 이름과 동일하게 해주어야 합니다.

 

작성한 yaml 파일을 적용하여 Pod 를 생성합니다.

# oc apply -f deployment_volume.yaml

deployment.apps/app-example created

 

생성된 Pod 를 확인합니다.

# oc get pod
NAME                      READY   STATUS    RESTARTS   AGE
app-example-5589d49b8d-j77kc   1/1     Running   0          4s

 

4) 마운트 확인

/data 에 저장된 데이터가 유지되고, 용량이 1Gi 로 제한 되고 있는지 확인해봅니다.

 

(NFS 서버에서)

테스트 파일을 하나 만들었습니다.

# ll /data
합계 4
-rw-r--r-- 1 root root 3  5월 12 15:16 test.txt

 

(Pod 에서)

Pod 이름을 확인하고 쉘 접속을 합니다.

# oc get pod
NAME                      READY   STATUS    RESTARTS   AGE
app-example-5589d49b8d-j77kc   1/1     Running   0          90s

# oc rsh app-example-5589d49b8d-j77kc

 

마운트 디렉토리로 이동합니다.

$ cd /data_client

 

디렉토리를 만들지 않아도 deployment yaml 에 지정한 디렉토리가 자동 생성되어 있습니다.
$ pwd
/data_client

 

NFS 서버에서 생성한 파일이 보이는 것을 확인하였습니다.
$ ls -al
total 4
drwxr-xr-x. 2 root root 21 May 12 06:16 .
dr-xr-xr-x. 1 root root 47 May 12 07:31 ..
-rw-r--r--. 1 root root  3 May 12 06:16 test.txt

* 참고

Pod 에서 보이는 시간이 국제 표준시로 출력됩니다. (한국보다 9시간 느림)

일단 넘어가고, 추후에 한국 시간으로 출력하는 방법을 찾으면 업데이트 하겠습니다.

 

 

반응형

댓글()

[Openshift] Pod (Container) 에 도메인 및 SSL 인증서 추가하기

리눅스/OpenShift|2023. 5. 10. 11:28
반응형

컨테이너에 외부 접근을 가능하게 하려면  라우트 (route) 를 생성하면 됩니다.

하지만 기본 라우트 도메인은 Pod 이름과 클러스터명을 기반으로 생성됩니다.

형식) <route명>-<프로젝트명>.apps.<클러스터명>

결과) python-sample-project412.apps.az1.sysdocu.kr

 

 

1. Ingress 생성

별도의 도메인을 추가하여 접근 가능하도록 하는 방법은 Ingress 를 생성하는 방법입니다.

Ingress 생성시 Route 경로가 추가 생성됩니다. 마찬가지로 Ingress 삭제시 함께 생성되었던 Route 도 같이 삭제 됩니다.

예제는 도메인 두개를 더 추가하는 방법으로 진행했으며, 아래 내용으로 Ingress yaml 파일을 작성하였습니다.

서비스 이름과 포트는 oc get service 명령으로 확인해서 입력해줘야 합니다.

 

# vi ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: python-sample
  namespace: project412
spec:
  rules:
  - host: sysdocu.kr
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: python-sample
            port:
              number: 8080
  - host: www.sysdocu.kr
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: python-sample
            port:
              number: 8080

 

작성한 파일을 적용합니다.

# oc apply -f ingress.yaml

ingress.networking.k8s.io/python-sample created

 

Ingress 생성을 확인합니다.

# oc get ingress

NAME            CLASS    HOSTS                       ADDRESS                            PORTS   AGE
python-sample      sysdocu.kr,www.sysdocu.kr router-default.apps.az1.sysdocu.kr   80      20s

 

추가된 Route 를 확인합니다.

# oc get route
NAME                  HOST/PORT                                    PATH   SERVICES        PORT            TERMINATION   WILDCARD
python-sample         python-sample-project412.apps.az1.sysdocu.kr          python-sample   8080                          None
python-sample-2ktlf   sysdocu.kr                                   /      python-sample   python-sample                 None
python-sample-rg89r   www.sysdocu.kr /      python-sample   python-sample                 None

 

이제 추가된 도메인으로 컨테이너 접근이 가능하지만

외부 DNS 에 해당 서버 IP 로 연결이 되어 있는지 확인해 봐야 합니다.

 

 

2. SSL 인증서 추가

인증서를 사용하는 프로토콜로 연결하기 위해서는 SSL 인증서를 발급받은 후에 OCP 서버에서 secret 을 생성해야 합니다.

무료 SSL 인증서 발급은 별도의 포스팅을 확인해주세요.

- https://sysdocu.tistory.com/1546

- https://sysdocu.tistory.com/1730

- https://sysdocu.tistory.com/1781

 

secret 생성시 인증서 경로를 지정합니다.

# oc create secret tls sysdocussl --cert=/root/ssl/cert1.pem --key=/root/ssl/privkey1.pem

secret/sysdocussl created

 

위에서 테스트 했던 Ingress 삭제 후 아래 내용으로 yaml 파일을 다시 작성하였습니다.

작성할때 서비스 이름과 포트는 oc get service 명령으로 확인해서 입력해줘야 합니다.

# oc delete ingress python-sample

# vi ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: python-sample
  namespace: project412
spec:
  tls:
  - hosts:
    - www.sysdocu.kr
    secretName: sysdocussl
  rules:
    - host: www.sysdocu.kr
      http:
        paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: python-sample
              port:
                number: 8080

 

작성된 yaml 파일을 적용합니다.

# oc apply -f ingress.yaml

ingress.networking.k8s.io/python-sample created

 

Ingress 생성을 확인합니다.

# oc get ingress
NAME            CLASS    HOSTS            ADDRESS                            PORTS     AGE
python-sample   <none>   www.sysdocu.kr router-default.apps.az1.sysdocu.kr   80, 443   87s

 

추가된 Route 를 확인합니다.

# oc get route
NAME                  HOST/PORT                                    PATH   SERVICES        PORT            TERMINATION     WILDCARD
python-sample         python-sample-project412.apps.az1.sysdocu.kr          python-sample   8080                            None
python-sample-cq6w6   www.sysdocu.kr /      python-sample   python-sample   edge/Redirect   None

 

이제 웹브라우저에서 추가된 도메인으로 접속하면 SSL 인증서 확인이 가능합니다.

https://www.sysdocu.kr

 

반응형

댓글()

[참고] Openshift 의 Service 와 Route 차이점 / Ingress 와 Route 차이점

리눅스/OpenShift|2023. 5. 10. 10:27
반응형

1. Openshift 에서 Service 와 Route 의 차이점

 

1) 서비스 (Service)

노출된 서비스에 대한 내부 클러스터 IP를 생성하고, 클러스터 내에서 해당 서비스를 사용할 수 있는 DNS 이름을 제공합니다.

서비스는 이러한 내부 IP 및 DNS 이름을 사용하여, 클러스터 내에서 포드(Pod) 간 통신을 할 수 있도록 합니다.

2) 라우트 (Route)

서비스를 클러스터 외부로 노출시키는 방법 중 하나입니다. 라우트는 클러스터 내부의 서비스를 외부에서 접근 가능한 URL로 노출시키는 역할을 합니다. 라우트를 생성하면 외부에서 해당 URL로 접근할 수 있으며, 이를 통해 클러스터 내부에 있는 서비스를 사용할 수 있습니다.

 

3) 정리
간단하게 말하자면 아래와 같습니다.

- 서비스 : 클러스터 내에서 포드 간 통신을 위한 논리적인 개념

- 라우트 : 외부에서 클러스터 내부의 서비스에 접근하기 위한 논리적인 개념
- 사용법 : 클러스터 내부에서만 사용해야 하는 서비스의 경우에는 서비스만 생성하고, 외부에서 접근이 필요한 경우에는 라우트를 생성하면 됩니다.

- 생성 순서 : 라우트는 서비스가 존재해야 생성 가능합니다. 서비스가 없다면 먼저 서비스를 생성해주어야 합니다.

 

 

2. Openshift 에서 Ingress 와 Route 의 차이점

 

1) 인그레스 (Ingress)

클러스터 외부에서 내부로 들어오는 네트워크 트래픽을 컨트롤러가 실행 중인 서비스로 라우팅하는 방법을 정의하는 API 오브젝트입니다.

Ingress 는 일반적으로 http(s) 요청을 처리하며 http(s) 요청을 서비스로 라우팅하고 SSL 암호화 및 트래픽 로드밸런싱과 같은 기능을 제공합니다. 따라서 Ingress 는 외부에서 클러스터로의 트래픽을 효과적으로 관리하고 컨트롤할 수 있도록 도와줍니다.

 

2) 라우트 (Route)

서비스를 클러스터 외부로 노출시키는 방법 중 하나입니다. 라우트는 클러스터 내부의 서비스를 외부에서 접근 가능한 URL로 노출시키는 역할을 합니다. 라우트를 생성하면 외부에서 해당 URL로 접근할 수 있으며, 이를 통해 클러스터 내부에 있는 서비스를 사용할 수 있습니다.

 

3) 비교

Ingress 와 Route 는 둘 다 클러스터 외부에서 클러스터 내부에 있는 서비스에 접근할 수 있도록 해주는 기능을 제공합니다.

다음은 Ingress 와 Route 의 차이점입니다.

 

- Ingress 는 http 와 https 프로토콜을 지원하고 Route 는 http, https, TLS 등 다양한 프로토콜을 지원합니다.
- Ingress 는 클러스터 레벨에서 관리하며, Route 는 프로젝트 내에서 관리됩니다.
- Ingress 는 Nginx, Traefik, Istio 등과 같은 인그레스 컨트롤러를 사용하여 구현되며, Route 는 OpenShift Router 를 사용하여 구현됩니다.
- Ingress 는 서비스의 라벨 셀렉터를 기반으로 경로를 분배하며, Route 는 서비스를 기반으로 경로를 분배합니다.

  또한 Route 는 서비스 포트와 경로를 연결하여 사용자가 노출시키려는 서비스를 선택할 수 있습니다.
- Ingress 는 기본적으로 Kubernetes API 오브젝트이며, Route 는 Openshift API 오브젝트입니다.

 

따라서 Ingress와 Route는 비슷한 역할을 하지만, 세부적인 구현 방식과 관리 방법에서 차이가 있습니다.

 

반응형

댓글()

[참고] Openshift 의 oc new-project 와 oc create ns 의 차이점

리눅스/OpenShift|2023. 5. 10. 09:04
반응형

Openshift 에서는 프로젝트를 만들기 위한 명령어 oc new-project 와 oc create ns (namespace) 를 제공하고 있으며 이 두 명령어는 기본적으로 동일한 결과를 가져옵니다.


모두 새로운 프로젝트 (Project) / 네임스페이스 (Namespace) 를 생성하는 명령어로 사용법도 거의 동일합니다.

다만 "oc new-project" 명령어는 프로젝트 (Project) 를 생성할 때 기본적으로 몇 가지 설정 값을 지정해 줍니다.

예를 들어, "oc new-project" 명령어는 프로젝트 (Project) 에 대한 일부 RBAC (Role-Based Access Control) 권한을 생성하고, 프로젝트 (Project) 를 위한 라벨 (label) 을 자동으로 추가합니다.

반면에 "oc create ns" 명령어는 단순히 네임스페이스 (Namespace) 를 생성하는 명령어로, 추가적인 설정이나 라벨 (label) 을 지정하지 않습니다.

따라서 두 명령어를 사용하는 것은 개인적인 선호나 상황에 따라 다를 수 있지만, 일반적으로는 두 명령어 모두 같은 결과를 가져오며, 기능적인 차이는 크지 않습니다.

 

 

[명령어로 확인하기]

 

1) 생성

# oc new-project cdh1
Now using project "cdh1" on server "https://api.az1.sysdocu.kr:6443".

You can add applications to this project with the 'new-app' command. For example, try:

    oc new-app rails-postgresql-example

to build a new example application in Ruby. Or use kubectl to deploy a simple Kubernetes application:

    kubectl create deployment hello-node --image=k8s.gcr.io/e2e-test-images/agnhost:2.33 -- /agnhost serve-hostname

# oc create ns cdh2
namespace/cdh2 created

 

2) RoleBinding 확인

파란색 부분에서 차이가 보입니다.

 

# oc get rolebinding -n cdh1
NAME                    ROLE                               AGE
admin                   ClusterRole/admin                  5m52s
system:deployers        ClusterRole/system:deployer        5m51s
system:image-builders   ClusterRole/system:image-builder   5m51s
system:image-pullers    ClusterRole/system:image-puller    5m51s

 

# oc get rolebinding -n cdh2
NAME                    ROLE                               AGE
system:deployers        ClusterRole/system:deployer        5m45s
system:image-builders   ClusterRole/system:image-builder   5m45s
system:image-pullers    ClusterRole/system:image-puller    5m45s

 

3) Project 속성 확인

파란색 부분에서 차이가 보입니다.

 

# oc describe ns cdh1
Name:         cdh1
Labels:       kubernetes.io/metadata.name=cdh1
              pod-security.kubernetes.io/audit=restricted
              pod-security.kubernetes.io/audit-version=v1.24
              pod-security.kubernetes.io/warn=restricted
              pod-security.kubernetes.io/warn-version=v1.24
Annotations:  openshift.io/description: 
              openshift.io/display-name: 
              openshift.io/requester: system:admin
              openshift.io/sa.scc.mcs: s0:c27,c9
              openshift.io/sa.scc.supplemental-groups: 1000720000/10000
              openshift.io/sa.scc.uid-range: 1000720000/10000
Status:       Active

No resource quota.

No LimitRange resource.

 

# oc describe ns cdh2
Name:         cdh2
Labels:       kubernetes.io/metadata.name=cdh2
              pod-security.kubernetes.io/audit=restricted
              pod-security.kubernetes.io/audit-version=v1.24
              pod-security.kubernetes.io/warn=restricted
              pod-security.kubernetes.io/warn-version=v1.24
Annotations:  openshift.io/sa.scc.mcs: s0:c27,c14
              openshift.io/sa.scc.supplemental-groups: 1000730000/10000
              openshift.io/sa.scc.uid-range: 1000730000/10000
Status:       Active

No resource quota.

No LimitRange resource.

 

 

반응형

댓글()

curl 명령으로 telegram 메세지 보내기 (Bot Token, Chat ID 필요)

리눅스/OS 일반|2023. 4. 26. 13:31
반응형

Bot ID 와 Chat ID 를 알고 있는 상태라면 아래와 같이 간단히 보낼 수 있습니다.

 

# curl https://api.telegram.org/bot<Bot Token>/sendMessage -d "chat_id=<Chat ID>" -d "text=<보낼 메세지>"

 

반응형

댓글()

[Openshift] 미터링 도구 Prometheus + AlertManager 알람 (webhook + telegram)

리눅스/OpenShift|2023. 4. 24. 10:10
반응형

Kubernetes 의 표준 모니터링 도구라 불리는 프로메테우스 (Prometheus) 는 리소스로부터 metirc 을 수집하고 모니터링 하는 기능을 제공합니다. 여기에 AlertManager 를 설치하면 이벤트 발생시 알림을 받을 수 있고, 웹 UI 대시보드인 Grafana 를 설치하면 시각화된 모니터링 페이지를 구성 할 수 있게 됩니다.

Prometheus 는 Kubernetes 에서 많이 사용하지만 Openshift 명령어인 OC (Openshift CLI) 도 쿠버네티스 기반으로 동작을 하므로 본 매뉴얼에서는 oc 명령 위주로 작업을 진행하도록 하겠습니다.

Kubernetes 사용자는 oc 명령 대신 kubectl 로 바꿔 사용하면 됩니다.

 

공식 페이지

https://prometheus.io

https://grafana.com/

 

 

1. kube-state-metrics 설치

 

kube-state-metrics 는 Kubernetes 클러스터 내 오브젝트에 대한 지표 (metrics) 정보를 수집하는데 사용되는 필수적인 도구 입니다.

이 도구는 Kubernetes API 서버에 쿼리를 보내서 클러스터의 리소스 상태 및 구성 정보를 수집하고, 이 정보를 Prometheus 와 같은 모니터링 시스템에서 사용할 수 있는 형식으로 출력해 줍니다.
kube-state-metrics 를 사용하면 클러스터 내부의 다양한 (Node, Pod, ReplicaSet, Deployment, StatefulSet, Service 등) 리소스 상태를 쉽게 모니터링할 수 있습니다.

kube-state-metrics 를 사용하기 위해 아래 파일을 모두 작성합니다.

https://github.com/kubernetes/kube-state-metrics/tree/main/examples/standard 에서 배포하는 내용으로 작성하였으며 테스트하며 몇군데 수정하였습니다.

 

kube-state-metrics 를 어떤 버전으로 사용해야 하는지는 https://github.com/kubernetes/kube-state-metrics 에서 참고해주세요.

# oc version

Client Version: 4.12.0
Kustomize Version: v4.5.7
Server Version: 4.12.0
Kubernetes Version: v1.25.4+77bec7a

 

1) ClusterRoleBinding 생성

# vi metrics-crb.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: 2.7.0
  name: kube-state-metrics
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kube-state-metrics
subjects:
- kind: ServiceAccount
  name: kube-state-metrics
  namespace: kube-system

 

2) ClusterRole 생성

# vi metrics-cr.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: 2.7.0
  name: kube-state-metrics
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  - secrets
  - nodes
  - pods
  - services
  - serviceaccounts
  - resourcequotas
  - replicationcontrollers
  - limitranges
  - persistentvolumeclaims
  - persistentvolumes
  - namespaces
  - endpoints
  verbs:
  - list
  - watch
- apiGroups:
  - apps
  resources:
  - statefulsets
  - daemonsets
  - deployments
  - replicasets
  verbs:
  - list
  - watch
- apiGroups:
  - batch
  resources:
  - cronjobs
  - jobs
  verbs:
  - list
  - watch
- apiGroups:
  - autoscaling
  resources:
  - horizontalpodautoscalers
  verbs:
  - list
  - watch
- apiGroups:
  - authentication.k8s.io
  resources:
  - tokenreviews
  verbs:
  - create
- apiGroups:
  - authorization.k8s.io
  resources:
  - subjectaccessreviews
  verbs:
  - create
- apiGroups:
  - policy
  resources:
  - poddisruptionbudgets
  verbs:
  - list
  - watch
- apiGroups:
  - certificates.k8s.io
  resources:
  - certificatesigningrequests
  verbs:
  - list
  - watch
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
- apiGroups:
  - storage.k8s.io
  resources:
  - storageclasses
  - volumeattachments
  verbs:
  - list
  - watch
- apiGroups:
  - admissionregistration.k8s.io
  resources:
  - mutatingwebhookconfigurations
  - validatingwebhookconfigurations
  verbs:
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - networkpolicies
  - ingressclasses
  - ingresses
  verbs:
  - list
  - watch
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - list
  - watch
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - clusterrolebindings
  - clusterroles
  - rolebindings
  - roles
  verbs:
  - list
  - watch

 

3) ServiceAccount 생성

# vi metrics-sa.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: 2.7.0
  name: kube-state-metrics
  namespace: kube-system

 

4) Deployment 생성

# vi metrics-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: 2.7.0
  name: kube-state-metrics
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: kube-state-metrics
  template:
    metadata:
      labels:
        app.kubernetes.io/name: kube-state-metrics
        app.kubernetes.io/version: 2.7.0
    spec:
      automountServiceAccountToken: true
      containers:
      - image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.7.0
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 5
          timeoutSeconds: 5
        name: kube-state-metrics
        ports:
        - containerPort: 8080
          name: http-metrics
        - containerPort: 8081
          name: telemetry
        readinessProbe:
          httpGet:
            path: /
            port: 8081
          initialDelaySeconds: 5
          timeoutSeconds: 5
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          readOnlyRootFilesystem: true
          runAsNonRoot: true
          runAsUser: 65534
          seccompProfile:
            type: RuntimeDefault
      nodeSelector:
        kubernetes.io/os: linux
      serviceAccountName: kube-state-metrics

 

5) Service 생성

외부에서 수집이 잘 되고 있는지 확인하기 위해 yaml 파일에서 NodePort 형식으로 31000 포트 설정을 추가 합니다.

# vi metrics-service.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: 2.7.0
  name: kube-state-metrics
  namespace: kube-system
spec:
  type: NodePort
  ports:
  - name: http-metrics
    port: 8080
    targetPort: http-metrics
    nodePort: 31000
  - name: telemetry
    port: 8081
    targetPort: telemetry
  selector:
    app.kubernetes.io/name: kube-state-metrics

 

생성한 5개의 yaml 파일을 적용합니다.

# oc apply -f metrics-crb.yaml
# oc apply -f metrics-cr.yaml

# oc apply -f metrics-sa.yaml
# oc apply -f metrics-deployment.yaml
# oc apply -f metrics-service.yaml

 

kube-state-metrics Service 상태를 확인합니다.

kube-state-metrics 의 ClusterIP 는 Prometheus 에서 접근하기 위해 사용하므로 메모하거나 기억해 둡니다.

# oc get service -n kube-system
NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
kube-state-metrics   NodePort    172.30.224.58   <none>        8080:31000/TCP,8081:32325/TCP   4m30s
kubelet              ClusterIP   None            <none>        10250/TCP,10255/TCP,4194/TCP    12d

 

kube-state-metrics Pod 상태를 확인합니다.

# oc get pod -n kube-system -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP            NODE                    NOMINATED NODE   READINESS GATES
kube-state-metrics-74cfc87b67-9nwpd   1/1     Running   0          4m38s   10.128.3.13   worker01.az1.sysdocu.kr   <none>           <none>

 

웹브라우저로 호스트명과 포트 31000 을 이용해 접속하면 metrics (수집 항목) 와 healthz (데몬 상태) 메뉴가 보입니다.

http://worker01.az1.sysdocu.kr:31000

- metrics (수집 항목) : 주석이 해제되어 있는 항목만 수집합니다.

- healthz (데몬 상태) : OK 라고 떠야 합니다.

 

 

2. Prometheus 설치

 

아래 예제파일에서 kube-state-metrics IP 를 제외하고 그대로 적용해도 동작하므로 그대로 복사하여 적용해 보도록 합니다.

다음과 같은 내용의 yaml 파일을 모두 만들어 놓습니다.

 

1) ClusterRole 생성

프로메테우스 컨테이너가 쿠버네티스 API 에 접근할 수 있도록 권한을 부여 합니다.

# vi prometheus-cr.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus
  namespace: monitoring
rules:
- apiGroups: [""]
  resources:
  - nodes
  - nodes/proxy
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
- apiGroups:
  - extensions
  resources:
  - ingresses
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics"]
  verbs: ["get"]

 

* 설명

metadata: name : prometheus 라는 이름의 클러스터 역할을 생성하고 모니터링 권한을 정의 합니다.

metadata: namespace : 역할을 생성할 위치를 말합니다. 본 매뉴얼에서는 monitoring 이라는 프로젝트 (네임스페이스) 로 정했습니다.

rules: resources : ClusterRole 이 접근할 리소스를 지정합니다. (여기에서는 nodes, nodes/proxy, services, endpoints, pods 지정)
rules: verbs: ["get", "list", "watch"] : 리소스에 대한 허용된 동작을 지정합니다. (여기에서는 get, list, watch 동작 허용)
rules: apiGroups: resources: verbs: ["get", "list", "watch"] : configmaps 리소스에 대한 동작을 허용합니다. (여기에서는 get, list, watch 동작 허용)
rules: nonResourceURLs: verbs: ["get"] : /metrics URL 에 대한 get 동작을 허용합니다.

 

2) ClusterRoleBinding 생성

# vi prometheus-crb.yaml

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: default
  namespace: monitoring

 

* 설명

ClusterRoleBinding : monitoring 이름의 클러스터 역할 연결을 생성합니다.

                                   > monitoring 프로젝트 내의 prometheus 라는 클러스터 역할 연결 생성

                                   > monitoring 이라는 클러스터 역할 지정

 

3) ConfigMap 생성

ConfigMap 은 크게 두가지로 나뉘는데 이는 아래와 같습니다.

- prometheus.rules : 알람을 받기위한 조건을 설정합니다.

- prometheus.yml : 수집할 metric 종류와 주기를 설정합니다.

 

# vi prometheus-cm.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-server-conf
  labels:
    name: prometheus-server-conf
  namespace: monitoring
data:
  prometheus.rules: |-
    groups:

    # Pod CPU ====================
    - name: Pod CPU alert # 알림 그룹
      rules:
      - alert: Pod CPU usage rate over 90% # AlertManager 에 출력되는 알람 제목
        # 알림 트리거 조건
        expr: sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.9
        for: 1m # 지정된 시간 (1분) 동안 조건이 유지되어야 알람 트리거 발생
        labels:
          severity: warning # 종류로는 fatal, warning, error, critical, info, debug 외에 custom 입력가능
        # 주석. 생략 가능
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 80%
        expr: 0.9 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.8
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 70%
        expr: 0.8 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.7
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 60%
        expr: 0.7 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.6
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 50%
        expr: 0.6 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.5
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 40%
        expr: 0.5 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.4
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 30%
        expr: 0.4 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.3
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 20%
        expr: 0.3 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.2
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}

      - alert: Pod CPU usage rate over 10%
        expr: 0.2 >= sum(rate(container_cpu_usage_seconds_total{pod!=""}[1m])) by (namespace, pod) > 0.1
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod CPU usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}


    # 제대로 종료되지 않은 Pod 확인 ====================
    - name: Pod state
      rules:
      - alert: Pods blocked in terminating state
        expr: count(kube_pod_deletion_timestamp) by (namespace, pod) * count(kube_pod_status_reason{reason="NodeLost"} == 0) by (namespace, pod) > 0
        for: 5m
        labels:
          severity: notice
        annotations:
          summary: Pods blocked in terminating state
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} blocked in Terminating state.

    # Pod Memory ====================
    - name: Pod Memory alert
      rules:
      - alert: Pod Memory usage rate over 1G
        expr: sum(rate(container_memory_usage_bytes{pod!=""}[1m])) by (namespace, pod) > 1000000000 # 1G 이상
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: Pod Memory usage is high
          description: Pod {{ $labels.namespace }}/{{ $labels.pod }} value is {{ $value }}"

    # Node CPU ====================
    - name: Node CPU Alert
      rules:
      - alert: Node CPU usage rate over 90%
        expr: (100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)) > 90
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "High Node CPU Usage"
          description: "The CPU usage of the node {{ $labels.node }} is above 50%."

    # 시스템 다운 ====================
    - name: Instances down alert
      rules:
      - alert: Instance is Down
        expr: up == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} down" # 여기에서 labels.instance 는 115.68.142.103:6443 형태로 출력
          description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes." # 여기에서 labels.job 은 kubernetes-service-endpoints 형태로 출력


  # 프로메테우스 동작에 대한 configuration
  prometheus.yml: |-

    # 전반적인 설정
    global:
      scrape_interval: 5s     # scrape 하는 주기 (기본 1분)
      evaluation_interval: 5s # Rules 들을 평가하는 주기 (기본 1분)

    # 규칙을 로딩하고 evaluation_interval 설정에 따라 정기적으로 평가
    rule_files:
      - /etc/prometheus/prometheus.rules

    # Alert 보낼곳 (AlertManager) 설정
    alerting:
      alertmanagers:
      - scheme: http
        static_configs:
        - targets:
          - "alertmanager.monitoring.svc:9093"

    # metrics 정보를 가져오는 곳 (job_name 단위로 구분)
    scrape_configs:
      - job_name: 'kubernetes-apiservers'
        kubernetes_sd_configs:
        - role: endpoints
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        relabel_configs:
        - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
          action: keep
          regex: default;kubernetes;https

      - job_name: 'kubernetes-nodes'
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        kubernetes_sd_configs:
        - role: node
        relabel_configs:
        - action: labelmap
          regex: __meta_kubernetes_node_label_(.+)
        - target_label: __address__
          replacement: kubernetes.default.svc:443
        - source_labels: [__meta_kubernetes_node_name]
          regex: (.+)
          target_label: __metrics_path__
          replacement: /api/v1/nodes/${1}/proxy/metrics

      - job_name: 'kubernetes-pods'
        kubernetes_sd_configs:
        - role: pod
        relabel_configs:
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
          action: keep
          regex: true
        - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
          action: replace
          target_label: __metrics_path__
          regex: (.+)
        - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
          action: replace
          regex: ([^:]+)(?::\d+)?;(\d+)
          replacement: $1:$2
          target_label: __address__
        - action: labelmap
          regex: __meta_kubernetes_pod_label_(.+)
        - source_labels: [__meta_kubernetes_namespace]
          action: replace
          target_label: kubernetes_namespace
        - source_labels: [__meta_kubernetes_pod_name]
          action: replace
          target_label: kubernetes_pod_name

      - job_name: 'kube-state-metrics'
        static_configs:
          - targets: ['172.30.224.58:8080']

      - job_name: 'kubernetes-cadvisor'
        scheme: https
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        kubernetes_sd_configs:
        - role: node
        relabel_configs:
        - action: labelmap
          regex: __meta_kubernetes_node_label_(.+)
        - target_label: __address__
          replacement: kubernetes.default.svc:443
        - source_labels: [__meta_kubernetes_node_name]
          regex: (.+)
          target_label: __metrics_path__
          replacement: /api/v1/nodes/${1}/proxy/metrics/cadvisor

      - job_name: 'kubernetes-service-endpoints'
        kubernetes_sd_configs:
        - role: endpoints
        relabel_configs:
        - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
          action: keep
          regex: true
        - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
          action: replace
          target_label: __scheme__
          regex: (https?)
        - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
          action: replace
          target_label: __metrics_path__
          regex: (.+)
        - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
          action: replace
          target_label: __address__
          regex: ([^:]+)(?::\d+)?;(\d+)
          replacement: $1:$2
        - action: labelmap
          regex: __meta_kubernetes_service_label_(.+)
        - source_labels: [__meta_kubernetes_namespace]
          action: replace
          target_label: kubernetes_namespace
        - source_labels: [__meta_kubernetes_service_name]
          action: replace
          target_label: kubernetes_name


 

위 설정에서 클러스터 오브젝트 메트릭스를 수집하는 kube-state-metrics 의 targets 에 Cluster IP 를 설정하였습니다.

원래 도메인으로 설정해야 Pod 가 재시작 되면 바뀌는 IP 도 자연스럽게 연결이 될텐데, service 생성하는 부분에서 테스트가 잘 안되었으므로 추후 업데이트 하기로하고, 우선 위에서 메모 또는 기억해 두었던 kube-state-metrics 의 Cluster IP 와 8080 포트를 설정합니다.

      - job_name: 'kube-state-metrics'
        static_configs:
          - targets: ['172.30.224.58:8080']

그리고 {{ $labels.pod }} 와 같은 코드를 사용할때 빈값이 전송 될경우, expr 쿼리가 올바른지 살펴봐야 합니다. Prometheus 대시보드나 promql 명령어 (아래에서 설명) 를 이용해 PromQL 쿼리 결과값을 확인해보세요. Element 에 pod 값이 있어야 {{ $labels.pod }} 로 값을 넘겨줄 수 있습니다.

 

4) Deployment 생성

Pod 를 생성하기 위한 설정입니다.

# vi prometheus-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus-deployment
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus-server
  template:
    metadata:
      labels:
        app: prometheus-server
    spec:
      containers:
        - name: prometheus
          image: prom/prometheus:v2.44.0
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            runAsNonRoot: true
            seccompProfile:
              type: RuntimeDefault
          args:
            - "--config.file=/etc/prometheus/prometheus.yml"
            - "--storage.tsdb.path=/prometheus/"
          ports:
            - containerPort: 9090
          volumeMounts:
            - name: prometheus-config-volume
              mountPath: /etc/prometheus/
            - name: prometheus-storage-volume
              mountPath: /prometheus/
      volumes:
        - name: prometheus-config-volume
          configMap:
            defaultMode: 420
            name: prometheus-server-conf
        - name: prometheus-storage-volume
          emptyDir: {}

 

5) Service 생성

컨테이너 외부에서 프로메테우스로 접근하기 위한 네트워크 설정입니다.

# vi prometheus-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: prometheus-service
  namespace: monitoring
  annotations:
      prometheus.io/scrape: 'true'
      prometheus.io/port:   '9090'
spec:
  selector:
    app: prometheus-server
  type: NodePort
  ports:
    - port: 8080
      targetPort: 9090
      nodePort: 30003

 

6) Node-exporter (DaemonSet & Service) 생성

Node-exporter 는 노드 서버 자체의 다양한 메트릭 (CPU, 디스크, 메모리의 사용률, 네트워크 트래픽 등) 을 수집할 수 있습니다.

이러한 정보를 수집하여 운영 중인 노드의 성능과 리소스 사용량을 모니터링 할 수 있습니다.

스케쥴링되는 노드 (Pod 가 생성되는 노드) 마다 Pod 가 자동 설치됩니다.

아래와 같은 내용으로 DaemonSet, Service 두 개를 함께 작성합니다.

# vi prometheus-node-exporter.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring
  labels:
    k8s-app: node-exporter
spec:
  selector:
    matchLabels:
      k8s-app: node-exporter
  template:
    metadata:
      labels:
        k8s-app: node-exporter
    spec:
      containers:
      - image: prom/node-exporter
        name: node-exporter
        ports:
        - containerPort: 9100
          protocol: TCP
          name: http
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
---
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: node-exporter
  name: node-exporter
  namespace: monitoring
spec:
  ports:
  - name: http
    port: 9100
    nodePort: 31672
    protocol: TCP
  type: NodePort
  selector:
    k8s-app: node-exporter

 

이제 monitoring 네임스페이스를 만들고 작성해두었던 모든 yaml 파일을 적용합니다.

# oc create ns monitoring
# oc apply -f prometheus-cr.yaml

# oc apply -f prometheus-crb.yaml

# oc apply -f prometheus-cm.yaml
# oc apply -f prometheus-deployment.yaml

# oc apply -f prometheus-service.yaml
# oc apply -f prometheus-node-exporter.yaml

 

생성된 Pod 를 확인합니다. 서비스를 NodePort 형태로 생성했으므로 외부 접근을 위해 라우트 생성을 추가로 할 필요가 없습니다.

node-exporter Pod 을 보면 각 노드 (worker01, worker02) 에 하나씩 배포되었기 때문에 각 노드의 컨테이너 모니터링이 가능합니다.

prometheus-deployment 이름으로 된 Pod 의 호스트명과 포트 30003 으로 직접 접근이 가능합니다.

# oc get pod -n monitoring -o wide
NAME                                     READY   STATUS    RESTARTS   AGE   IP             NODE                    NOMINATED NODE   READINESS GATES
node-exporter-57djp                      1/1     Running   0     12m   10.131.0.184   worker02.az1.sysdocu.kr   <none>           <none>
node-exporter-w5s8d                      1/1     Running   0     12m   10.128.2.239   worker01.az1.sysdocu.kr   <none>           <none>
prometheus-deployment-859bc6d5c7-dm5nv   1/1     Running   0     24m   10.128.2.237   worker01.az1.sysdocu.kr   <none>           <none>

 

웹브라우저로 접속하면 여러가지 메뉴 이용이 가능합니다.

http://worker01.az1.sysdocu.kr:30003

 

프로메테우스 대시보드 > Status > Targets 에서도 kube-state-metrics 의 메트릭 정보가 정상적으로 수집되는 것을 확인할 수 있습니다.

kube-state-metrics (1/1 up)

 

참고)

대시보드 Alerts 메뉴에서는 임계치 설정 등 모니터링 설정 상태가 출력됩니다.

그래프 메뉴는 값이 생성되지 않으면 출력되지않지만 가장 많은 데이터를 볼 수 있는 항목은 아래와 같습니다.

Graph > 풀다운메뉴에서 container_memory_cache 선택 후 'Execute' 클릭 > 아래 'Graph' 탭을 누르면 그래프가 출력되는것이 보입니다.

 

7) 로그 보관일 변경

프로메테우스 대시보드 > Status > Runtime & Build Information 으로 들어가면 Storage retention 값이 15d (default) 로 되어 있습니다. 15일치 로그만 보관하겠다는 의미인데, 서비스로 제공하기에 적은 기간이므로 이부분을 10y (10년) 으로 변경 설정해 보겠습니다.

* 참고사항

- 프로메테우스에서 지원되는 최소 보존 시간은 2시간입니다.

- 설정한 보관 기간까지 데이터가 꽉 찬 상태에서는 오래된 데이터가 자동 삭제되지 않고, 더이상 데이터가 수집되지 않는 현상이 발생합니다.

- 그러다가 보관 기간을 늘리면 멈춘 상태에서 수집되지 않았던 데이터를 한번에 수집하게 됩니다.

 

현재 상태를 확인합니다.

# oc -n openshift-monitoring get sts prometheus-k8s -oyaml |grep retention
        - --storage.tsdb.retention.time=15d

 

yaml 파일을 작성하고 적용합니다.

기존 환경에서 retention time 부분만 추가했습니다.

# vi retention.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-monitoring-config
  namespace: openshift-monitoring
data:
  config.yaml: |
    prometheusK8s:
      retention: 10y            # 기간으로 제한
      retentionSize: 10GiB # 용량으로 제한

 

용량 설정이 필요한 경우 retention 아래 retentionSize : 10GiB 와 같이 추가 설정이 가능합니다.

작성한 yaml 파일을 적용합니다.

# oc apply -f retention.yaml 
configmap/cluster-monitoring-config created

 

변경사항을 확인합니다.

# oc -n openshift-monitoring get sts prometheus-k8s -oyaml |grep retention 
        - --storage.tsdb.retention.time=10y

 

이후에는 바뀐 설정값으로 동작을 하게 되는데, (2h 로 조정 후 테스트로 확인) 아까 살펴본 Prometheus 대시보드에서는 그대로 15d 로 출력됩니다. 이는 버그로 확인됩니다. (인터넷 상에서도 누군가도 버그 같다고 함)

 

 

3. Node-Exporter 설치

 

이번에는 클러스터 내부 메트릭 정보 수집이 아닌, 외부 특정 서버의 메트릭을 수집하는 방법입니다.

저는 OCP 서버 (bastion) 를 모니터링 하기 위해서 해당 부분 설정을 진행하였습니다.

모니터링 대상이 프로메테우스의 데이터 포맷을 지원하지 않는 경우 Exporter 라는 에이전트를 설치해야 하는데

node-exporter, mysql-exporter, nginx-exporter, redis-exporter 등 여러 종류가 있어 목적에 맞는 에이전트를 설치해야 합니다.

 

여기에서는 서버 자원 메트릭을 가져오기 위해 Node-Exporter 바이너리 파일을 배치하는 방식으로 설치할 예정이며

클러스터 내의 프로메테우스와 연동시켜 모니터링 해보도록 하겠습니다.

 

1) 설치

(OCP 서버에서)

다운로드 : https://prometheus.io/download/#node_exporter

 

다운로드 사이트에서 나온 최신버전 (현재기준 v1.5.0) 의 리눅스용 파일 URL 을 복사하고 서버에서 다운로드를 합니다.

# wget https://github.com/prometheus/node_exporter/releases/download/v1.5.0/node_exporter-1.5.0.linux-amd64.tar.gz

 

압축을 해제하고 실행파일을 시스템 폴더로 이동합니다.

# tar xvzf node_exporter-1.5.0.linux-amd64.tar.gz

# cd node_exporter-1.5.0.linux-amd64

# mv node_exporter /usr/local/bin/

 

부팅시 자동 실행되도록 서비스 데몬으로 등록합니다.

# cd /etc/systemd/system/
# vi node_exporter.service

[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter

[Install]
WantedBy=multi-user.target

 

node_exporter 라는 계정을 생성하여 구동 권한을 줍니다.

이렇게하면 특정 계정으로만 실행되므로 시스템 보안성을 향상 시킬 수 있습니다.
# useradd --no-create-home --shell /bin/false node_exporter
# chown node_exporter.node_exporter /usr/local/bin/node_exporter

 

systemd 를 재호출하고, node_exporter 데몬을 부팅시 자동 실행되도록 합니다.
그리고 현재 데몬을 시작합니다.

# systemctl daemon-reload
# systemctl enable node_exporter
# systemctl start node_exporter

 

서비스 상태와 포트를 확인합니다.

# systemctl status node_exporter |grep Active

   Active: active (running) since 화 2023-04-25 08:24:21 KST; 5min ago

# netstat -nltp |grep node_exporter
tcp6       0      0 :::9100                 :::*                    LISTEN      14500/node_exporter 

 

2) 프로메테우스와 연동

클러스터의 프로메테우스에서 서버 모니터링이 되도록 ConfigMap yaml 설정 파일을 수정합니다.

원래의 파일이 있던 위치로 돌아가 맨 하단에 job_name 을 추가해 줍니다.

# cd

# vi prometheus-cm.yaml


...
  prometheus.yml: |-
...
    scrape_configs:
...
      - job_name: 'server-info'
        static_configs:
        - targets: ['115.68.142.99:9100']

 

* 설명

scrape_configs 에 job_name 을 추가 해줍니다.

- Exporter 가 제공하는 Endpoint 가 /metrics 라면 metrics_path 의 설정을 생략 가능합니다.
- http 로 연결할 경우 스키마 설정을 생략 가능합니다.

- targets : 두개 이상의 서버를 등록하려면 targets 에 아래와 같은 형태로 추가하면 됩니다.

호스트명으로 입력 할 수 있습니다.

['192.168.10.2:9100', '192.168.10.3:9100', 'worker02.az1.sysdocu.kr:9100']

저는 OCP (bastion) 서버 한대에서만 node_exporter 를 설치했기 때문에 IP 한 개의 값만 입력하였습니다.

 

변경한 설정값을 적용하기 위해 yaml 파일을 다시 적용하고, 이미 생성된 pod 를 삭제하여 재생성되도록 합니다.

# oc apply -f prometheus-cm.yaml

 

Pod 재가동은 Pod 를 삭제하여 Deployment 의 replicas 에 의해 자동 생성 되도록 진행하는 것입니다.

# oc get pod -n monitoring
NAME                                     READY   STATUS    RESTARTS   AGE
node-exporter-57djp                      1/1     Running   0          17h
node-exporter-w5s8d                      1/1     Running   0          17h
prometheus-deployment-859bc6d5c7-dm5nv   1/1     Running   0          17h

 

# oc delete pod prometheus-deployment-859bc6d5c7-dm5nv -n monitoring
pod "prometheus-deployment-859bc6d5c7-dm5nv" deleted

 

# oc get pod -n monitoring
NAME                                     READY   STATUS    RESTARTS   AGE
node-exporter-57djp                      1/1     Running   0          17h
node-exporter-w5s8d                      1/1     Running   0          17h
prometheus-deployment-859bc6d5c7-lgrwj   1/1     Running   0          16s

 

Pod 를 재생성해서 worker node 가 바뀌었을 수 있으므로 재확인 합니다.

# oc get pod -n monitoring -o wide

NAME                                     READY   STATUS    RESTARTS   AGE   IP             NODE                    NOMINATED NODE   READINESS GATES
node-exporter-57djp                      1/1     Running   0     17h   10.131.0.184   worker02.az1.sysdocu.kr              
node-exporter-w5s8d                      1/1     Running   0     17h   10.128.2.239   worker01.az1.sysdocu.kr              
prometheus-deployment-859bc6d5c7-dm5nv   1/1     Running   0     11m   10.128.2.237   worker02.az1.sysdocu.kr    <none>        <none>

 

주소와 포트 번호를 이용해 웹브라우저로 접속합니다.

http://worker02.az1.sysdocu.kr:30003

프로메테우스 대시보드 > Status > Targets 에 접근하면 server-info 의 메트릭 정보가 정상적으로 수집되는 것을 확인할 수 있습니다.

server-info (1/1 up)

 

 

4. AlertManager 설치

 

AlertManager 는 Prometheus 에서 진행하는 알림 프로젝트 입니다.

본 매뉴얼에서는 모니터링 상세 설정을 하고 설정한 임계치 초과시 webhook 서버를 통해 telegram 알람을 받는 형식으로 진행하였지만 AlertManager 는 E-mail, Slack, PagerDuty, Pushover, Webhook 등 다양한 형태의 알림 방법을 지원하므로 목적에 맞는 설정 방법을 찾아서 설정하면 됩니다.

AlertManager 에서 webhook 서버를 통하지 않고 telegram 메세지를 바로 보내는 방법은 사전에 지정한 관리자에게만 발송하도록 되어 있어 Pod 사용자가 모두 다를 경우에는 AlertManager 에서 telegram 메세지 보내기에 적합하지 않은것 같습니다.

그래서 custom 작업이 가능한 별도의 webhook 서버를 만들어 사용했습니다.

 

1) 설치

AlertManager 서비스를 생성할때 ConfigMap 을 두개 작성하는데, 하나는 알람을 받을 대상, 하나는 알람 메세지 정보입니다.

구성을 위해 ConfigMap 두개와 Pod 생성을 위한 Deployment, 네트워크 연결을 위한 Service 를 작성합니다.

# vi alertmanager-cm.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: alertmanager-config
  namespace: monitoring
data:
  config.yml: |-
    global:
      resolve_timeout: 5m

    route:
      group_by: ['alertname'] # prometheus.yml 의 targets -labels의 label_name 을 의미
      group_wait: 10s            # inhibit 조건 발생에 대한 중복을 방지하기 위한 알림 발생 전 대기시간 (여기에서는 inhibit_rules 미사용)
      group_interval: 5m        # 알림 간 시간 간격 설정
      repeat_interval: 1h        # 알림 재발생
      receiver: webhook         # 알림 설정 대상

    receivers:
      - name: webhook
        webhook_configs:
          - url: 'http://alert.sysdocu.kr/telegram_send.php' # 알림을 웹훅 서버로 전송 (전송이 안될경우 도메인말고 IP 로 해볼것)
            send_resolved: false

    templates:
      - '/etc/alertmanager/config/*.tmpl'

 

* 설명

- route: receiver: 값과 receivers: name: 값은 같아야 합니다.

- webhook_configs 의 url 은 별도의 웹서버입니다. 저는 webhook 서버에서 AlertManager 가 보내주는 데이터를 받을 telegram_send.php 을 만들었습니다. 이 파일은 데이터를 용도에 맞게 처리하게 되며 (telegram 메세지 발송), 처리된 결과를 다시 AlertManager 로 응답할 필요는 없습니다.

- send_resolved 는 Alertmanager가 알림의 해결 상태 (resolved) 를 전송할지 여부를 나타내는 옵션입니다. false 의 경우 알람이 발생되었을때만 웹훅 서버로 전송하고, 해결된 알람에 대해서는 전송하지 않습니다.

- url: 도메인으로 동작이 안될 경우 oc logs 명령으로 로그를 확인해보세요. 저의 경우 status code 503 에러 등 연결이 안된 경우에 도메인을 IP 로 바꿔 넣으니 잘 동작하였습니다. Pod 나 클러스터 어디에서도 DNS 응답이 잘 되었지만, 실제로 해보면 모든 도메인이 OCP 서버를 바라보고 있었는데, 원인을 찾게되면 내용을 추가하겠습니다.

 

[참고]  웹훅 서버 만들기 ==========

용도에 따라 웹훅 서버라고 불리지만 그냥 웹서버라고 이해하면 됩니다.

nginx 또는 httpd 웹서버에 데이터를 처리할 php 정도만 설치 하면 됩니다.

DocumentRoot 웹소스 디렉토리에 아래 코드를 만들어 넣으면 됩니다.

(전체 POST 데이터를 알림하는 소스함. 추후 용도에 맞게 원하는 데이터만 추출하여 Telegram 보낼 수 있게 해보세요)

# vi telegram_send.php

<?php
// AlertManager 로부터 받은 데이터를 처리 (알람, 기록 등) 합니다.
// 응답을 반환하지 않아도 됩니다.

$postBody = file_get_contents('php://input'); // POST 데이터 전체 읽기

function telegram_send($chat_id, $msg) {
      $bot_token = "1234567890:ABHjBqhcBSUlY30NwIhiwyxwOEBHoHOsIGs"; // Telegram 봇 토큰
      $params = 'chat_id=' . $chat_id . '&text=' . urlencode($msg);
      $TELEGRAM = 'https://api.telegram.org/bot' . $bot_token . '/sendMessage';
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $TELEGRAM);
      curl_setopt($ch, CURLOPT_HEADER, false);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_TIMEOUT, 5);
      curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
      curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
      $return = curl_exec($ch);
      curl_close($ch);
      return $return;
}

// podName 을 확인하고 DB 에서 ChatID 를 가져와 메세지를 작성해야하는데
// 여기에서는 DB 연결 부분은 제외하고, 임의로 ChatID 와 받은 알람 전체 내용을 입력 했습니다.
telegram_send("10000000", $postBody);
?>

 

웹훅 서버가 잘 동작하는지 확인하기 위해 샘플 json파일을 만들어 curl 명령으로 POST 전송을 해볼 수 있습니다.

# echo '{"site": "CPU over 10%"}' > sample.json
# curl -i \
-H "Host: alert.sysdocu.kr:80" \
-H "User-Agent: Alertmanager/0.25.0" \
-H "Content-Type: application/json" \
--request POST \
--data @sample.json \
http://alert.sysdocu.kr:80/telegram_send.php

============================

 

계속해서 AlertManager 설치를 이어 나가겠습니다.

# vi alertmanager-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: alertmanager
  namespace: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      app: alertmanager
  template:
    metadata:
      name: alertmanager
      labels:
        app: alertmanager
    spec:
      securityContext:
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: alertmanager
        image: prom/alertmanager:latest
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
          runAsNonRoot: true
        args:
          - "--config.file=/etc/alertmanager/config.yml"
          - "--storage.path=/alertmanager"
        ports:
        - name: alertmanager
          containerPort: 9093
        volumeMounts:
        - name: config-volume
          mountPath: /etc/alertmanager
      volumes:
      - name: config-volume
        configMap:
          name: alertmanager-config

 

# vi alertmanager-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: alertmanager
  namespace: monitoring
  annotations:
      prometheus.io/scrape: 'true'
      prometheus.io/path:   /
      prometheus.io/port:   '8080'
spec:
  selector:
    app: alertmanager
  type: NodePort
  ports:
    - port: 9093
      targetPort: 9093
      nodePort: 30005

 

작성한 yaml 파일을 적용하여 AlertManager 를 가동합니다.

# oc apply -f alertmanager-cm.yaml
# oc apply -f alertmanager-deployment.yaml
# oc apply -f alertmanager-service.yaml

 

Pod 정보에 출력된 호스트명과 포트 30005 번으로 접근하면 AlertManager 웹페이지가 출력됩니다.

# oc get pod -n monitoring -o wide
NAME                                     READY   STATUS    RESTARTS   AGE     IP             NODE                    NOMINATED NODE   READINESS GATES
alertmanager-5c694d4f4d-x5gqz            1/1     Running   0          5m43s   10.131.0.253   worker02.az1.sysdocu.kr   <none>           <none>
node-exporter-57djp                      1/1     Running   0          25h     10.131.0.184   worker02.az1.sysdocu.kr   <none>           <none>
node-exporter-w5s8d                      1/1     Running   0          25h     10.128.2.239   worker01.az1.sysdocu.kr   <none>           <none>
prometheus-deployment-859bc6d5c7-pshwz   1/1     Running   0          7h32m   10.128.3.22    worker01.az1.sysdocu.kr   <none>           <none>

 

웹브라우저로 접속이 가능합니다.

http://worker02.az1.sysdocu.kr:30005

 

이제 서버에 부하를 발생시켜 알람 메세지가 telegram 으로 수신되고, 웹페이지 로그 출력도 잘 되는지 확인해 보도록 합니다.

 

2) 알람 발생

CPU 사용률 10%, Memory 사용률 50% 를 임계치로 정하고, 해당 리소스 사용량이 초과되면 webhook 서버를 통해 telegram 메세지를 발송하게 설정하였습니다.

Stress Pod 를 생성하고 부하를 일으켜 실제 telegram 메세지가 잘 발송되는지 확인합니다.

(Stress Pod 생성이 번거로울 경우 아래 '임의 로그 생성' 부분을 참고하세요)

 

Pod 가 생성되면 stress -c 1 명령이 실행되도록 합니다. (CPU 1 core 부하 100%)

이는 컨테이너 생성시부터 아래 작성할 Deployment 삭제시까지 부하를 일으키게 됩니다.

# cat Dockerfile

FROM docker.io/progrium/stress
CMD ["-c", "1"]

 

# docker build -t stress-app .

# docker tag stress-app default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/stress
# docker push default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/stress

 

stress 응용프로그램을 배포하기 위해 yaml 파일을 작성합니다.

# vi stress-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: stress
  labels:
    app: stress
  namespace: project412
spec:
  containers:
  - name: stress
    image: default-route-openshift-image-registry.apps.az1.sysdocu.kr:5000/project412/stress
    ports:
      - containerPort: 80
    resources:
      limits:
        cpu: "1"
        memory: "1Gi"
    securityContext:

      allowPrivilegeEscalation: false
      capabilities:
        drop:
        - ALL
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      runAsUser: 65534
      seccompProfile:
        type: RuntimeDefault

  imagePullSecrets:
  - name: sysdocu

 

Resources 에 제한 (CPU 1개, Memory 1G) 을 두어 작성하였습니다.

작성한 yaml 파일을 적용면 Deployment 와 Pod 가 생성됩니다.

# oc apply -f stress-pod.yaml

pod/stress created

 

Pod 상태가 Running 중으로 잘 구동 되어야 합니다.

# oc get pod -o wide

NAME                             READY   STATUS    RESTARTS   AGE    IP             NODE                    NOMINATED NODE   READINESS GATES
stress-668d86686d-4l7dm   1/1     Running   0          15s    10.131.1.84    worker02.az1.sysdocu.kr   <none>           <none>

 

Prometheus 대시보드에 가면 Alerts 페이지에서 아래와 같이 모니터링 알림 조건을 만족하는 노드가 1개 있다고 출력됩니다.

/etc/prometheus/prometheus.rules > Container CPU alert
Container CPU usage rate over 10% (1 active)

 

AlertManager 웹페이지 Alerts 메뉴에서도 Prometheus 정보를 받아와서 출력 해주는 것을 볼 수 있습니다.

alertname="Container CPU usage rate over 10%" 1 alerts

 

이와 동시에 Telegram 메세지가 잘 수신 되었습니다.

 

* 임의 로그 생성

Pod 자원을 사용하지 않고 임의로 AlertManager 에 로그 이벤트를 밀어 넣는 간단한 방법이 있습니다.

명령어 설치 방법은 아래와 같습니다.

# wget https://github.com/prometheus/alertmanager/releases/download/v0.16.1/alertmanager-0.16.1.linux-amd64.tar.gz

# tar xvzf alertmanager-0.16.1.linux-amd64.tar.gz

# cd alertmanager-0.16.1.linux-amd64

# mv amtool /usr/local/bin/

# amtool --version
amtool, version 0.16.1 (branch: HEAD, revision: 571caec278be1f0dbadfdf5effd0bbea16562cfc)
  build user:       root@3000aa3a06c5
  build date:       20190131-15:05:40
  go version:       go1.11.5

 

수동으로 탐지 메세지를 입력하는 명령입니다.

AlertManager Pod 의 호스트명과 포트 30005 번을 이용하고, yaml 파일에서 설정했던 alertname 과 severity 를 맞추어 줍니다.

명령 실행 후 바로 리스트에서 확인되지 않고 몇 초 기다려야 합니다.

# amtool --alertmanager.url=http://worker02.az1.sysdocu.kr:30005 alert add alertname="Container CPU usage rate over 10%" severity="warning"

 

알람 데이터가 잘 입력되었는지 확인합니다.

# amtool alert --alertmanager.url=http://worker02.az1.sysdocu.kr:30005
Alertname                                      Starts At                Summary  
Container CPU usage rate over 10%  2023-04-28 02:06:10 UTC

 

원래 Prometheus 에서 탐지된 정보를 AlertManager 로 보내주는 방식이나, 테스트를 위해 AlertManager 로 직접 알람 정보를 넣었습니다.

그래서 Prometheus 대시보드에서는 안보이고 AlertManager 대시보드에만 임계치 초과 정보가 확인 가능합니다.

물론 AlertManager 로 입력된 데이터 Telegram 으로 수신이 잘 되었습니다.

 

[참고] amtool 명령어 사용 방법 ==========

(1) 알람 리스트 출력 (간단)

AlertManager 의 호스트명과 포트번호 30005 를 이용하여 알람 리스트를 출력하면 위에서 입력했던 임의의 알람이 확인됩니다.

(amtool 명령어 설치는 위 '임의 로그 생성' 에서 확인하세요)
# amtool alert --alertmanager.url=http://worker02.az1.sysdocu.kr:30005
Alertname                                         Starts At                Summary                
Container CPU usage rate over 10%  2023-04-28 02:06:10 UTC

 

(2) 알람 리스트 출력 (json 형태로 출력)

# amtool alert --alertmanager.url=http://worker02.az1.sysdocu.kr:30005 -o json
[{"labels":{"alertname":"Container CPU usage rate over 10%","severity":"warning"},"annotations":{},"startsAt":"2023-04-28T02:06:10..445599906Z","endsAt":"2023-04-28T02:09:10.445599906Z","generatorURL":"","status":{"state":"active","silencedBy":null,"inhibitedBy":null},"receivers":["telegram"],"fingerprint":"bba57b61590c89ba"}]

 

(3) 특정 알람 silence 처리

여러가지 항목을 함께 사용해 조건에 맞는것만 silence 할 수 있지만 여기에서는 유일한 키인 fingerprint 값을 이용해 처리하겠습니다.

comment 는 이유를 적는 메모란인데 silence 처리하기 위해 반드시 필요합니다. 확인했다는 뜻으로 ok 라고 간단히 적겠습니다.

# amtool silence add --alertmanager.url=http://worker02.az1.sysdocu.kr:30005 fingerprint="bba57b61590c89ba" --comment=ok
70ce770c-2280-4ef3-87fb-5f99bd812eb9


(4) silence 리스트 출력
# amtool silence --alertmanager.url=http://worker02.az1.sysdocu.kr:30005
ID                                    Matchers                      Ends At                  Created By  Comment  
70ce770c-2280-4ef3-87fb-5f99bd812eb9  fingerprint=bba57b61590c89ba  2023-04-28 03:08:28 UTC  root        ok       

(5) silence 만료 처리 (삭제)

silence 의 ID 값으로 삭제를 진행합니다.
# amtool silence expire 70ce770c-2280-4ef3-87fb-5f99bd812eb9 --alertmanager.url=http://worker02.az1.sysdocu.kr:30005

==================================

 

 

5. PromQL 사용 방법

 

Prometheus 에서 kube-state-metrics 를 통해 수집하는 각각의 Pod 자원 사용량을 조회하는 방법을 알아보겠습니다.

수집된 데이터는 PromQL 이라고 하는 쿼리 언어를 사용하여 조회 할 수 있습니다.

아래 예제들을 참고하여 원하는 데이터를 알람 발송 설정해 보세요.

 

1) API 로 데이터 조회

Prometheus API 를 통해 JSON 형태의 데이터를 가져올 수 있습니다.

다음은 Namespace 별 Pod 개수를 가져오는 쿼리 입니다.

# curl -X GET " http://worker01.az1.sysdocu.kr:30003/api/v1/query?query=count(kube_namespace_created)"

 

2) PromQL 로 데이터 조회

또는 PromQL 이라는 명령어를 이용해 데이터를 가져올 수 있는데, 시각적으로 보기 좋게 테이블 형태로 출력 해줍니다.

쿼리를 사용하기 위해 PromQL 을 설치합니다.

https://github.com/nalbury/promql-cli 에서 최신버전의 PromQL 과 사용방법 확인이 가능합니다.

# wget https://github.com/nalbury/promql-cli/releases/download/v0.3.0/promql-v0.3.0-linux-amd64.tar.gz

# tar xvzf promql-v0.3.0-linux-amd64.tar.gz

# mv promql /usr/local/bin/

# promql --version
promql version v0.2.1  // 배포를 잘못했는지 이전 버전이 출력 됌

 

Prometheus 대시보드에서 PromQL 을 사용할 수 있지만 CLI 환경에서도 사용해 보기 위해 PromQL 을 설치했습니다.

간단하게 Namespace 의 개수를 조회하고 출력이 잘 되는지 확인합니다.

# promql --host "http://worker01.az1.sysdocu.kr:30003" 'count(kube_namespace_created)'
VALUE    TIMESTAMP
71       2023-05-26T09:13:39+09:00

 

현재시간으로 71개의 네임스페이스가 확인되었습니다.

Prometheus 대시보드의 쿼리 입력창 바로 아래에 사용가능한 쿼리 예시가 풀다운메뉴로 제공되고 있으며, 쿼리 사용을 위한 공식 Document URL  (https://prometheus.io/docs/prometheus/latest/querying/basics/) 도 있으므로 상세 설정이 필요하신 분은 참고하시기 바랍니다.

몇가지 Pod 관련 데이터를 더 조회해 보겠습니다.

 

형식) promql --host "http://worker01.az1.sysdocu.kr:30003" '<PromQL 쿼리문>'

형식에 아래 쿼리문을 대입하여 사용하면 됩니다.

- Pod 별 CPU 사용률 : sum(rate(container_cpu_usage_seconds_total{pod!="", container!="POD"}[5m])) by (pod)

- 특정 Pod 의 CPU 사용률 : sum(rate(container_cpu_usage_seconds_total{pod!="", container!="POD"}[5m])) by (pod)

- 특정 Pod 의 5분전 CPU 사용률 : sum(rate(container_cpu_usage_seconds_total{namespace="project412", pod="stress", container!="POD"}[5m] offset 5m)) by (pod)

- 특정 Namespace 및 Pod 의 한달간 CPU 사용률 : 

- 특정 Namespace 및 Pod 의 한달간 트래픽 사용률 : 

- Namespace 전체 개수 : count(kube_namespace_created)
- Pod 전체 개수 : count(count by(pod)(container_spec_memory_reservation_limit_bytes{pod!=""}))

- Namespace 별 Pod 개수 : count(kube_pod_info) by (namespace)

특정 네임스페이스 (monitoring) 내에서 조회

- Pod 들의 CPU 사용률 : sum(rate(container_cpu_usage_seconds_total{namespace="monitoring"}[5m])) by (pod)

- Pod 들의 Memory 사용량 : sum(container_memory_usage_bytes{namespace="monitoring"}) by (pod)

- Pod 들의 In-bound 트래픽 양 (byte) : sum(rate(container_network_receive_bytes_total{namespace="monitoring"}[5m])) by (pod)

- Pod 들의 Out-bound 트래픽 양 (byte) : sum(rate(container_network_transmit_bytes_total{namespace="monitoring"}[5m])) by (pod)

 

3) Promtool 로 조회

가장 필요로 했던 부분이 Pod 의 일일 평균 CPU 사용량을 한달치 가져오는 것인데 PromQL 이나 Prometheus API 에서 원하는 값을 가져오기가 어려웠습니다. 날짜로 정렬해주지 않고 최종 데이터 하나만 출력되기 때문이였는데요.

다양한 조건으로 쿼리를 사용할 수 있도록 공식 사이트에서 제공되는 Promtool 을 사용하면 쉽게 해결이 됩니다.

Promtool 공식 홈페이지에 가면 다운로드 파일과 사용 방법을 확인 할 수 있습니다.
저는 linux amd64 버전으로 다운로드 하고 설치하였습니다.

URL : https://prometheus.io/docs/prometheus/latest/command-line/promtool/

위 URL 에서 최신 버전의 파일을 확인하고 다운로드 합니다.

# wget https://github.com/prometheus/prometheus/releases/download/v2.44.0/prometheus-2.44.0.linux-amd64.tar.gz
# tar xvzf prometheus-2.44.0.linux-amd64.tar.gz
# mv prometheus-2.44.0.linux-amd64/promtool /usr/local/bin/
# promtool --version
promtool, version 2.44.0 (branch: HEAD, revision: 1ac5131f698ebc60f13fe2727f89b115a41f6558)
  build user:       root@739e8181c5db
  build date:       20230514-06:18:11
  go version:       go1.20.4
  platform:         linux/amd64
  tags:             netgo,builtinassets,stringlabels

아래와 같이 쿼리를 사용하여 한달 치 데이터를 출력하였습니다. (일일 평균 CPU 사용률 한달치 출력)

형식) promtool query range <Prometheus서버:포트> <쿼리> --start=<시작시간 unix timestamp> --end=<종료시간 unix timestamp> --step=<조회간격>

# promtool query range http://worker01.az1.sysdocu.kr:30003 "avg(rate(container_cpu_usage_seconds_total{namespace='project412', pod='stress', container!='POD'}[1d]))" --start=1682866800 --end=1685545199 --step=1d
{} =>
0.062463003550851465 @[1685199600]
0.9981953068392649 @[1685286000]
0.9981756660420877 @[1685372400]
0.667332233021956 @[1685458800]

 

* 설명

2023-05-01 00:00:00 부터 2023-05-31 23:59:59 까지의 하루 평균 CPU 사용률 데이터를 가져오도록 하였으며 조회 간격은 1일입니다. 조회대상 stress Pod 는 1core 짜리이고, 1core 를 100% 부하 주도록 되어있는데 (부하율 1), 3일전 생성한 Pod 여서 금일까지 총 4개의 데이터가 출력되었으며, 금일은 시간이 다 안지났기 때문에 0.66 으로 데이터가 어제보다 작게 나왔습니다. 잘 출력이 되는 것 같습니다.

 

추가로 일일 out-bound 트래픽 (byte) 양을 집계 해보겠습니다.

트래픽 양을 측정하기 위해 사용되는 메트릭은 다음과 같습니다.
- container_network_receive_bytes_total : 컨테이너가 수신한 네트워크 바이트 수를 측정하는 메트릭입니다.
- container_network_receive_packets_total : 컨테이너가 수신한 네트워크 패킷 수를 측정하는 메트릭입니다.
- container_network_transmit_bytes_total : 컨테이너가 전송한 네트워크 바이트 수를 측정하는 메트릭입니다.
- container_network_transmit_packets_total : 컨테이너가 전송한 네트워크 패킷 수를 측정하는 메트릭입니다.

 

# promtool query range http://worker01.az1.sysdocu.kr:30003 "sum(increase(container_network_transmit_bytes_total{namespace='project412', pod='stress'}[1d]))" --start=1682866800 --end=1685545199 --step=1d
{} =>
70.12534720867937 @[1685199600]
1610.44330061364 @[1685286000]
1680.5090135203238 @[1685372400]
1120.3633424784455 @[1685458800]

 

출력된 값의 단위는 byte 입니다. 부하만 주는 용도이며 외부와의 연결이 전혀 없으므로 굉장히 낮은 트래픽 사용량을 보이고 있습니다.

 

반응형

댓글()

Openssl 로 자체 서명 인증서 (SSL) 생성하기

리눅스/OS 일반|2023. 4. 11. 11:42
반응형

OpenSSL 1.1.1 이상의 버전인지 확인하고 아닐 경우 addext 옵션 사용을 위해 업그레이들 해두면 좋습니다.

( https://sysdocu.tistory.com/1691 )

 

인증서 생성을 위해 아래 절차를 따릅니다.

# host_fqdn=www.sysdocu.kr
# cert_c="KR"                   // Country Name (C, 2 letter code)
# cert_s="Seoul"               // Certificate State (S)
# cert_l="Seoul"                // Certificate Locality (L)
# cert_o="Sysdocu"          // Certificate Organization (O)
# cert_ou="TechTeam"      // Certificate Organizational Unit (OU)
# cert_cn="${host_fqdn}"  // Certificate Common Name (CN)

 

미리 입력받은 변수값으로 인증서를 생성합니다.

생성할때 인증서 및 키 파일의 위치를 지정해줍니다.

# mkdir /root/ssl
# openssl req \
    -newkey rsa:4096 \
    -nodes \
    -sha256 \
    -keyout /root/ssl/sysdocu.key \
    -x509 \
    -days 365 \
    -out /root/ssl/sysdocu.crt \
    -addext "subjectAltName = DNS:${host_fqdn}" \
    -subj "/C=${cert_c}/ST=${cert_s}/L=${cert_l}/O=${cert_o}/OU=${cert_ou}/CN=${cert_cn}"

 

인증서 생성이 확인되었습니다.

# ll /root/ssl/
합계 12
-rw-r--r--. 1 root root 1952  4월  4 16:15 sysdocu.crt
-rw-------. 1 root root 1704  4월  4 16:15 sysdocu.key

 

반응형

댓글()

Openshift 4.12.0 MetalLB 로드발란서 설치 및 서비스 IP 대역 할당하기

리눅스/OpenShift|2023. 4. 6. 09:34
반응형

[ 참조 문서 ]

- 설치 : https://docs.openshift.com/container-platform/4.12/networking/metallb/metallb-operator-install.html

- 아이피 추가 : https://docs.openshift.com/container-platform/4.12/networking/metallb/metallb-configure-address-pools.html

 

AWS, MS Azure 등의 인프라에서 구성하는것이 아닌 BareMetal 형태의 단독 시스템들로 구성을 할 경우 LoadBalancer 제공을 위해 아래와 같이 추가 설정을 진행 할 수 있습니다.

클러스터 관리자는 MetalLB Operator 를 추가하여 클러스터 내의 MetalLB 인스턴스의 라이프사이클을 관리할 수 있습니다.

그러나 MetalLB 와 IP failover 는 호환되지 않습니다.

클러스터에서 IP failover 를 구성한 경우, Operator를 설치하기 전에 IP failover를 제거하는 단계를 수행해야 합니다. (제거 과정은 생략합니다)

 

 

1. MetalLB 설정

 

다음 명령을 실행하여 MetalLB Operator 네임스페이스를 만듭니다.

# oc create ns metallb-system
namespace/metallb-system created

 

OperatorGroup yaml 파일을 작성합니다.

# vi og.yaml

apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  name: metallb-operator
  namespace: metallb-system

 

작성한 yaml 파일을 적용합니다.

# oc apply -f og.yaml
operatorgroup.operators.coreos.com/metallb-operator created

 

Operator 그룹이 네임스페이스에 설치되어 있는지 확인합니다.

# oc get operatorgroup -n metallb-system
NAME               AGE
metallb-operator   8s

 

사용자 지정 리소스 (CR) 를 사용하여 YAML 파일을 저장합니다.

# vi metallb-sub.yaml

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: metallb-operator-sub
  namespace: metallb-system
spec:
  channel: stable
  name: metallb-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace

 

적용하여 Subscription 을 생성합니다.

# oc apply -f metallb-sub.yaml
subscription.operators.coreos.com/metallb-operator-sub created

 

네임스페이스 라벨을 붙입니다.

# oc label ns metallb-system "openshift.io/cluster-monitoring=true"
namespace/metallb-system labeled

 

설치 계획이 네임스페이스에 있는지 확인합니다.

# oc get installplan -n metallb-system
NAME            CSV                                    APPROVAL    APPROVED
install-56ph2   metallb-operator.4.12.0-202303231115   Automatic   true

 

아래 명령으로 상태를 확인하면 시간이 지나 Installing 에서 Succeeded 로 변경되는 것이 확인됩니다.

# oc get clusterserviceversion -n metallb-system
NAME                                   DISPLAY            VERSION               REPLACES   PHASE
metallb-operator.4.12.0-202303231115   MetalLB Operator   4.12.0-202303231115              Succeeded

 

 

2. 클러스터에서 MetalLB 시작하기

 

MetalLB 생성을 위한 yaml 파일을 작성합니다.

# vi MetalLB.yaml

apiVersion: metallb.io/v1beta1
kind: MetalLB
metadata:
  name: metallb
  namespace: metallb-system

 

yaml 파일을 적용하여 MetalLB 를 생성합니다.

# oc apply -f MetalLB.yaml
metallb.metallb.io/metallb created

 

컨트롤러 생성이 확인되었습니다.

# oc get deployment -n metallb-system controller
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
controller   1/1     1            1           45s

 

시간이 지나면서 speaker 준비 개수가 하나씩 오르는 것이 확인됩니다.

# oc get daemonset -n metallb-system speaker
NAME      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
speaker   5         5         5       5            5           kubernetes.io/os=linux   2m17s

 

 

3. Metal 을 위한 배포 사양

 

PriorityClass yaml 파일을 작성합니다.

여기에서는 high-priority 클래스를 사용합니다.

# vi PriorityClass.yaml

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000

 

작성한 yaml 파일을 적용합니다.
# oc apply -f PriorityClass.yaml 
priorityclass.scheduling.k8s.io/high-priority created

 

MetalLB yaml 파일을 작성합니다.

priorityClassName 에 위에서 적용한 metadata: name: 값을 입력합니다.

# vi MetalLBPodConfig.yaml

apiVersion: metallb.io/v1beta1
kind: MetalLB
metadata:
  name: metallb
  namespace: metallb-system
spec:
  logLevel: debug
  controllerConfig:
    priorityClassName: high-priority
    runtimeClassName: myclass
  speakerConfig:
    priorityClassName: high-priority
    runtimeClassName: myclass
  affinity:
      podAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchLabels:
             app: metallb
          topologyKey: kubernetes.io/hostname

 

작성한 yaml 파일을 적용합니다.

# oc apply -f MetalLBPodConfig.yaml
metallb.metallb.io/metallb configured

 

네임스페이스의 Pod 에 할당한 우선 순위 클래스를 표시합니다.

# oc get pods -n project412 -o custom-columns=NAME:.metadata.name,PRIORITY:.spec.priorityClassName
NAME                    PRIORITY
mysql-bd544cdb8-qvm59   <none>

 

 

4. MetalLB 배치에서의 Pod CPU 제한 설정

 

필요에 따라 다음에 포드 CPU 제한을 할당할 수 있습니다.

controller 와 speaker Pod 를 설정함으로써 MetalLB yaml 파일에서 CPU 제한을 정의 합니다.

controller 또는 speaker Pod 는 노드의 리소스를 관리하는 데 도움이 됩니다.

이를 통해 노드의 모든 Pod 가 워크로드 관리와 클러스터 하우스키핑에 필요한 컴퓨팅 리소스를 확보할 수 있습니다.

 

MetalLB yaml 파일을 작성합니다.

# vi CPULimits.yaml

apiVersion: metallb.io/v1beta1
kind: MetalLB
metadata:
  name: metallb
  namespace: metallb-system
spec:
  logLevel: debug
  controllerConfig:
    resources:
      limits:
        cpu: "200m"
  speakerConfig:
    resources:
      limits:
        cpu: "300m"

 

작성한 yaml 파일을 적용합니다.
# oc apply -f CPULimits.yaml 
metallb.metallb.io/metallb configured

 

Pod 이름을 확인하고 적용 상태를 자세하게 확인합니다.

# oc describe pod mysql-bd544cdb8-qvm59

(출력 생략)

 

 

5. 컨테이너 런타임 클래스 설정

 

선택적으로 컨테이너 런타임 클래스를 다음에 할당할 수 있습니다.

Windows 작업 부하에 대해서는 pod에 Windows 런타임 클래스를 할당할 수 있습니다.

이렇게 하면 pod 내의 모든 컨테이너가 이 런타임 클래스를 사용하게 됩니다.

 

RuntimeClass yaml 파일을 작성합니다.

# vi myRuntimeClass.yaml

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: myclass
handler: myconfiguration

 

작성한 yaml 파일을 적용합니다.
# oc apply -f myRuntimeClass.yaml 
runtimeclass.node.k8s.io/myclass created

 

MetalLB yaml 파일을 작성합니다.

# vi MetalLBRuntime.yaml

apiVersion: metallb.io/v1beta1
kind: MetalLB
metadata:
  name: metallb
  namespace: metallb-system
spec:
  logLevel: debug
  controllerConfig:
    runtimeClassName: myclass
    annotations: 
      controller: demo
  speakerConfig:
    runtimeClassName: myclass
    annotations: 
      speaker: demo

 

작성한 yaml 파일을 적용합니다.
# oc apply -f MetalLBRuntime.yaml
metallb.metallb.io/metallb configured

 

Pod 의 컨테이너 런타임을 표시하려면 다음 명령을 실행합니다.

# oc get pod -o custom-columns=NAME:metadata.name,STATUS:.status.phase,RUNTIME_CLASS:.spec.runtimeClassName

 

 

6. MetalLB Address Pool 추가

 

클러스터 관리자는 IP 주소 풀 (address pool) 을 추가하거나 수정, 삭제 할 수 있습니다.

MetalLB Operator 는 주소 풀 커스텀 리소스를 사용하여 MetalLB가 서비스에 할당할 수 있는 IP 주소를 설정합니다.

예제에서는 metallb-system 네임스페이스를 사용한다고 가정합니다.

 

IPAddressPool yaml 파일을 작성합니다.

# vi ipaddresspool.yaml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  namespace: metallb-system
  name: doc-example
  labels: 
    zone: az1
spec:
  addresses:
  - 115.68.142.121-115.68.142.126

 

작성한 yaml 파일은 MetalLB 의 IPAddressPool 리소스를 정의하는 예시입니다. 이 리소스는 MetalLB 에서 사용할 IP 주소 풀을 구성합니다. 각 IP 주소 풀은 addresses 필드에 지정된 IP 범위로 정의됩니다.

- metadata: labels: zone: 리소스에 할당할 라벨을 지정합니다.
- spec: addresses: IP 주소 풀을 지정하는 섹션입니다. 각 IP 주소 풀은 - 로 구분된 범위로 지정됩니다.

                              이 예시에서는 115.68.142.121 부터 115.68.142.126 까지의 IP 범위를 지정했습니다. (IP 6개를 로드발란서 IP 로 사용)

                              떨어져있는 IP 를 추가하고 싶을 경우 한 행을 더 추가하면 됩니다.
이렇게 정의된 IPAddressPool 리소스를 적용하면 MetalLB 에서 해당 IP 주소 풀을 사용하여 로드발란서 IP 주소를 할당할 수 있습니다.

 

작성한 yaml 파일을 적용합니다.

# oc apply -f ipaddresspool.yaml

ipaddresspool.metallb.io/doc-example created

 

추가된 Address Pool 을 확인합니다.

# oc describe -n metallb-system IPAddressPool doc-example

(출력 생략)

 

아래는 다른 적용 예시 입니다.

 

IPv4 와 CIDR 범위를 이용한 설정입니다.

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: doc-example-cidr
  namespace: metallb-system
spec:
  addresses:
  - 192.168.100.0/24
  - 192.168.200.0/24
  - 192.168.255.1-192.168.255.5

 

MetalLB는 풀에서 IP 주소를 자동으로 할당하지 않도록 autoAssign 필드를 false 로 설정 할 수 있습니다.

서비스를 추가할 때, 풀에서 특정 IP 주소를 요청하거나 어노테이션에서 풀 이름을 지정하여 풀에서 사용 가능한 임의의 IP 주소를 요청할 수 있습니다.

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: doc-example-reserved
  namespace: metallb-system
spec:
  addresses:
  - 10.0.100.0/28
  autoAssign: false

 

반응형

댓글()

Docker 컨테이너 생성하지 않고 이미지 쉘에 접근하기

반응형

Docker 이미지를 다운로드 받거나 아직 받지 않은 상태에서도 이미지명만 알고 있으면 쉘 접속이 가능합니다.

방법은 아래와 같습니다.

 

현재 다운로드 받은 이미지 확인

# docker images

docker.io/php                                                                  latest              3d07cacc45bb        8 days ago          485 MB

 

이미지 쉘 접속하기

예) docker run --rm -it <Docker 이미지명> sh

# docker run --rm -it docker.io/php sh

 

반응형

댓글()

httpd 2.4 동시접속자 수 제한 상향 조정

리눅스/APACHE|2023. 4. 5. 08:34
반응형

httpd 2.4 기준으로 테스트 하였으나 오랫동안 해온 방식이라 거의 대부분의 버전에서 적용될 것 같습니다.

httpd 2.4 의 경우 Thread 처리 방식이 세종류 (Prefork, Worker, Event) 있습니다.

소스파일을 수정하지 않으면 아무리 설정해도 높은값으로 구동이 안되고 특정 메세지 (AH00513: WARNING) 가 출력되는것을 볼 수 있습니다.

소스파일을 수정하고 컴파일 하면 메인보드 오버클럭 동작과 비슷하게 아파치 기본 한계치를 높여 좀 더 많은 사용자가 동시접속이 가능하게 할 수 있습니다. 다만 하드웨어 (CPU, RAM 등) 의 성능이 받춰줘야 많은 동시접속자를 수용해도 처리가 가능하므로, 저사양의 서버를 운영중인 분에게는 추천드리지 않습니다.

 

아파치를 설치하는 단계에서 조정해줘야 하는 부분이 있으므로 이미 설치하여 사용중인분은 페이지 맨 아랫부분 옵션 적용 먼저 해보고 Syntax 에러가 없으면 그대로 사용하셔도 됩니다.

에러가 발생하면 아파치를 재설치 해주어야 하는데, 아파치를 설치하기전 소스파일을 수정해야 합니다.

# wget https://archive.apache.org/dist/httpd/httpd-2.4.56.tar.gz

# tar xvzf httpd-2.4.56.tar.gz

# cd httpd-2.4.56

 

동시접속 최대값을 수정합니다.

여기에서는 2048명의 동시접속을 허용하도록 하겠습니다.

참고로 수정해야 할 곳 앞에 # 이 있는데 이는 주석이 아니므로 삭제하지 않도록 합니다.

# vi server/mpm/prefork/prefork.c

#define DEFAULT_SERVER_LIMIT 2048    // 기본값 : 256

 

# vi server/mpm/worker/worker.c

#define DEFAULT_SERVER_LIMIT 32    // 설정한 값에 64를 곱하면 최대 동시접속자 32 * 64 = 2048 (기본값 : 16)

 

# vi server/mpm/event/event.c

#define DEFAULT_SERVER_LIMIT 32    // 설정한 값에 64를 곱하면 최대 동시접속자 32 * 64 = 2048 (기본값 : 16)

 

httpd 설치는 생략합니다. 설치는 다른 포스팅을 참고해 주시고 ( https://sysdocu.tistory.com/397 )

./configure 명령 실행할때 아래 처럼 원하는 MPM 을 옵션으로 추가하면 됩니다.

--with-mpm=worker

아래는 httpd 설치 후 확인 방법입니다.

 

사용하는 MPM 종류

# /usr/local/apache/bin/apachectl -V |grep MPM
Server MPM:     worker

 

모듈 로드 상태

# /usr/local/apache/bin/httpd -t -D DUMP_MODULES |grep mpm
mpm_worker_module (static)

예제에서는 worker 를 사용하는것이 확인되었습니다.

# vi /usr/local/apache/conf/httpd.conf

Include conf/extra/httpd-mpm.conf    // 주석 해제

 

아래 값을 적절히 수정합니다. MaxRequestWorkers 부분이 최대 동시접속자 수 입니다.

# vi /usr/local/apache/conf/extra/httpd-mpm.conf

<IfModule mpm_worker_module>
    StartServers            32
    ServerLimit             64    // 기존에 없는 옵션이므로 추가해 줍니다
    MinSpareThreads        100
    MaxSpareThreads        500
    ThreadsPerChild         64
    MaxRequestWorkers     2048
    MaxConnectionsPerChild   0
</IfModule>

 

* 옵션 설명

- StartServers : Apache 서버 가동시 생성되는 프로세스 수

- ServerLimit : Apache 서버가 생성할 수 있는 최대 프로세스 수

                       값의 공식은 MaxRequestWorkers / ThreadsPerChild = ServerLimit 이지만 이와 같거나 큰 값으로 설정하는 것이 좋습니다.

                       (여기에서는 2048 / 64 = 32 이지만 두배 큰수로 64 를 입력)

                       이 값은 시스템의 하드웨어 성능과 용량에 따라 조정되어야 합니다.

- MinSpareThreads : 최소 유지 스레드 수

                                  프로세스는 항상 최소 설정값 (여기에서는 100) 만큼의 유휴 스레드를 유지하려고 노력합니다.

                                  이는 웹 서버의 성능을 유지하기 위해 필요한 최소한의 스레드 수입니다.

- MaxSpareThreads : 최대 유지 스레드 수

                                   웹 서버가 생성한 스레드 중에 유지할 수 있는 최대 스레드의 수 (여기에서는 500) 를 결정합니다.

                                   이 값 이상의 스레드가 생성되면, 일부 스레드는 자동으로 종료되어 시스템 자원을 절약합니다.

- ThreadsPerChild : 프로세스 당 스레드 수

                                ThreadsPerChild가 64로 설정되어 있고, MaxSpareThreads가 500으로 설정되어 있다면,

                                하나의 프로세스 내에서 최대 64개의 스레드를 생성할 수 있으며, 이 중 최대 500개의 스레드는 유지됩니다.

- MaxRequestWorkers : 최대 동시 접속자 수

                                      서버가 처리할 수 있는 최대 요청 수를 결정하는 설정으로, 이 값을 증가시키면 동시에 처리할 수 있는 요청 수가 증가합니다.

- MaxConnectionsPerChild : Apache 서버에서 한 프로세스가 처리할 수 있는 최대 연결 수 (0 : 무제한)

 

httpd 설정 문법에 이상여부를 체크해보고 데몬을 재시작하여 적용합니다.

# /usr/local/apache/bin/apachectl -t

Syntax OK

# /usr/local/apache/bin/apachectl restart

 

반응형

댓글()

Openshift yaml 파일로 Pod 생성시 보안 (권한) 에러 메세지

리눅스/OpenShift|2023. 4. 4. 14:56
반응형

[ 에러 ]

아래와 같은 yaml 파일을 작성하여 Pod 를 생성하려고 하였습니다.

# vi app.yaml

apiVersion: v1
kind: Pod
metadata:
  name: app3
spec:
  containers:
  - name: app33
    image: docker.io/php:7.4-apache
    ports:
    - containerPort: 80

 

Pod 생성 명령시 아래와 같은 에러가 출력되었습니다.

 

# oc apply -f app.yaml

Warning: would violate PodSecurity "restricted:v1.24": allowPrivilegeEscalation != false (container "app33" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "app33" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "app33" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "app33" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

 

 

[ 해결 ]

에러 파일에 대한 조치로 아래와 같이 다시 작성하여 Pod 를 정상적으로 생성하였습니다.

apiVersion: v1
kind: Pod
metadata:
  name: app4
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app44
    image: docker.io/php:7.4-apache
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      runAsNonRoot: true

 

* 설명
allowPrivilegeEscalation: 컨테이너가 프로세스의 권한 상승을 허용하지 않도록 설정합니다.
capabilities: 컨테이너가 사용할 수 있는 권한(capabilities)을 제한합니다. 여기에서는 모든 권한을 제한하도록 drop=["ALL"]로 설정합니다.
runAsNonRoot: 컨테이너가 root 권한으로 실행되지 않도록 설정합니다.
seccompProfile: 컨테이너가 사용하는 seccomp 프로필을 설정합니다. 여기에서는 type을 RuntimeDefault로 설정합니다.

# oc apply -f app.yaml

pod/app4 created

 

반응형

댓글()