이랜드 그룹 계열사 중 쇼핑몰로 유명한 NC백화점, 뉴코아아울렛등 23곳이 랜섬웨어 감염으로 휴점을 했다는 뉴스가 나왔다. 그런데, 뉴스 기사를 보고 의아한 생각이 들었던 것이 뉴스 기사에서는 이것을 ‘공격’으로 표현하고 있다는데 있다.
랜섬웨어는 몇해전부터 유명해진 방법이다. 대상이 되는 컴퓨터 시스템에서 활동해 관련 자료들을 전부 암호화 해버린다. 만일 암호화된 자료를 복호화 할려면 패스워드를 알아야 하는데, 랜섬웨어를 유포한 일당들은 이것을 빌미로 돈을 요구한다. 대부분 돈을 요구한데로 보내줬다고 하더라도 나몰라라 하는 경우가 많다.
랜섬웨어는 공격을 하는 형태가 아니다. 랜섬웨어의 주요 경로는 불법적인 소프트웨어 다운로드에 있다. 정식경로가 아닌 경로에서의 소프트웨어 다운로드는 그 소프트웨어가 어떤 변형을 가지고 있는지 보증하지 않는다. 두번째는 이메일이다. IT 업무를 하는데 있어 이메일은 중요한 수단인데, 업무용 이메일과 사적인 이메일을 함께 설정해 사용하는 경우가 많다.
랜섬웨어는 이렇게 알게 모르게 첨부된 형태의 프로그램이다. 단지 그 프로그램이 실행될 것이라고 알아차리지 못하는 것이다. 그래서 이런 형태를 공격이라고 보긴 어렵다. 감염이라는 말이 더 맞는 말이다.
‘감염’ 그건 곧 이랜드 그룹 ‘책임’
뉴스에서는 ‘공격’ 이라는 표현을 썼는데 분명 잘못된 것이다. 그런데, 왜 이런 공격이라는 표현을 쓰는 것일까? 답은 간단하다. ‘감염’ 이라는 표현을 쓸 경우에 이것은 이랜드 그룹이 IT 업무를 하는데 있어 보안상의 주의의무를 다하지 않아 발생된 책임을 지게 된다.
결국에 이랜드 그룹의 책임이 없다는 함의를 전달하기 위해서 ‘랜섬웨어 공격’ 이라고 표현한 것인데, 명백한 책임회피다.
기업은 자신이 하는 일에 대한 책임을 져야 한다. 아니 기업까지 갈 필요도 없이 사람도 마찬가지다. 특히나 IT 관련 기업들은 개인정보를 다루는 경우 뿐만 아니라 많은 사람들이 그 IT 기업이 운영하는 서비스에 의존해 생계를 유지하는 경우도 많다.
그런데, 한국에서 IT 기업의 책임을 묻거나 그것에 대해서 배상을 한 적은 단 한번도 없다. ‘배상’ 은 물질적인 책임, 정신적 책임에 대해서 보상을 하는 것을 말한다. 하지만 언제부터인가 IT 기업은 말로만 ‘사과’ 하고 끝이였다.
여론을 다루는 언론사마져 기업 책임에 대한 인식이 없다
기업이 책임을 다하지 않는다는 모습을 보일때에 사람들은 분노한다. 하지만 오래전부터 내려온 IT 기업의 개인정보 유출 사건과 대법원의 현실을 외면한 판결로 인해서 이제는 그러려니~ 하는 분위기다 팽배하다.
기업은 당연히 책임을 지려고 하지 않을 것이고 대법원이야 법대로 처리하는 곳이라고 한다면 여론을 다루는 언론사만이라도 ‘그러려니~’ 하는 시각을 가져서는 안되는 것 아닌가?
랜섬웨어 네이버 뉴스검색
언론들 마져도 랜섬웨어 ‘공격’ 이라고 하고 앉았으니 절망적이라고 봐야 한다. IT 를 잘 모르는 대부분의 국민들은 최선을 다하는 기업이 엄하게 공격을 받아서 영업에 지장을 받은 것으로 인식할게 뻔하지 않나.
이랜드 그룹사의 랜섬웨어 감염은 공격 받아 발생한 문제가 아니다. 이 말은 평소 이랜드 그룹사에서 IT 업무를 할때에 보안적인 측면에서 업무 프로세스가 없거나 설사 있다고 하더라도 업무하는데 지장을 준다는 이유로 이행하지 않았을 것이 분명하다.
이랜드 그룹사가 보안에 대한 업무를 제대로 하지 않는 바람에 랜섬웨어에 감염됐다는 것이 이번 사건의 본질이다. 이에 따른 영업 손실에 대한 배상은 당연한 것이다.
이랜드 그룹사 랜섬웨어 감염을 설명하는 댓글이랜드 그룹사 랜섬웨어 문제 언급 댓글
대충사는 인간들도 문제
프리랜서로 일을 하다 보면 다양한 인간 유형을 만난다. 10에 9명은 자신의 행동을 통제하려고 하지 않는다. IT 라는 업무는 나름대로 규격이 정해져 있다. 다른 분야는 잘 모르지만 IT 산업은 매우 체계적이여서 접근하기도 쉽고 배우기도 쉬운 편에 속한다.
하지만 IT 를 한다는 인간들 대부분이 그러한 업무를 하는데 있어서 개인적인 행동에 제약이 존재한다는 것을 배우려 하지 않는다.
대표적인 것이 이메일이다. 이랜드 그룹사에 경우에도 회사의 메일서버를 운영한다. 개인마다 회사 업무를 위한 메일을 발급하는데, 대부분 사람들이 자신의 업무용 PC 에 Outlook 과 같은 메일 클라이언트를 설치해 POP3 프로토콜을 이용해 메일을 사용한다.
문제는 이 Outlook 에 개인이 사용하는 메일들, 예를들어 네이버 메일, 다음 메일등도 함께 등록해 사용하는 사람들이 존재한다는데 있다.
업무용 PC 는 인터넷과 연결해 사용한다고 하더라도 사적인 일을 해서는 안된다. 하지만 Outlook 에 개인이 사용하는 이메일을 연결하는 행위자체가 문제가 된다는 인식이 없다.
업무용 PC 를 이용해 쇼핑을 하는 경우도 허다하다. 쇼핑을 하는데 무슨 문제가 되느냐 하겠지만 문제는 결제할때 발생한다. 그 말도 안되는 ActiveX 프로그램들을 죄다 설치해야 하는데, 이벤트를 진행하는 경우, 분초를 다투면서 업무는 둘째고 급하게 결제를 하는 인간들도 있다.
이미 업무용 PC 에는 회사에 보안 정책에 기반한 각종 보안 프로그램들이 작동되고 있는데, 쇼핑 결제를 하겠다고 설치한 ActiveX 가 작동되지 않을 경우 어떻게든 회사에서 설치한 보안 프로그램을 우회할려고 피나는 노력을 아끼지 않는 인간도 있다.
이것도 기업 책임
그런 인간유형을 활개치게 놔두는 것도 기업의 책임일 수밖에 없다. 이런 유형의 인간들을 집어내 내치는 것 또한 기업이 책임져야할 일이 아니겠나. 더 나가 그렇게 하지 못하도록 기업의 문화를 만들어내는 것도 기업의 책무다.
Jenkins 에서 Github 나 GitLab 와 연동하기 위해서 Generic WebHook Trigger 플러그인을 많이 사용한다. 검색을 해보면 사용법이 아주 많이 나오는데, 특정 브랜치(Branch) 에만 작동되게 하기 위해서 Execute Shell 를 활용하는 사례를 볼 수 있다.
하지만 Generic WebHook Trigger 플러그인 설정에서 그냥 특정 브랜치만 반응하도록 할 수 있다.
Post content parameters in Generic WebHook Trigger
제일 먼저 Post content parameters 에서 Variable 에 “ref”, Expression 에는 “$.ref” 를 적어주고 JSONPath 를 선택해 준다.
이것은 Github나 GitLab 가 jenkins 를 호출할때에 JSON 포맷으로 관련 데이터를 넘겨주게 된다. JSON 포맷이기 때문에 이 포맷에서 특정 값을 가지고 오기 위해 정규표현식을 사용할 수 있는데, “$.ref” 는 “refs/heads/master” 식의 값을 가지고 오게 된다. 그리고 이러한 값은 이 플러그인에서 $ref 라는 변수에 할당되게 된다.
대부분 이렇게 설정을 한 후에 Execute Shell 를 사용하는데, 그럴 필요가 없이 추가적인 설정을 다음과 같이 하면 된다.
Optional filter in Generic WebHook Trigger
Generic WebHook Trigger 플러그인 설정에서 좀 더 아래로 내려보면 “Optional filter” 이 있는데 여기에 Expression 에 브랜치를 “refs/heads/master” 라고 적어준다. 그리고 Text 에는 앞에서 설정한 변수명인 $ref 를 적어준다.
이렇게 하면 master 브랜치만을 체크해 이 플러그인이 작동되게 된다. 다른 브랜치에만 반응하도록 하기 위해서는 “refs/heads/[브랜치 이름]” 으로 적어 놓으면 된다.
Skipping bootstrap because certbot-auto isdeprecated on thissystem.
Your system isnotsupported by certbot-auto anymore.
Certbot cannot be installed.
Please visit https://certbot.eff.org/ to check for other alternatives.
위와같이 메시지를 내면서 실행되지 않는다. 검색을 해보면 snapd 를 설치해서 실행하는 방법을 소개하고 있지만, snapd 를 설치한다고 하더라도 letencrypt-auto 스크립트를 사용하는 것은 아니다.
letencrypt-auto 대신에 certbot 명령어를 이용하면 된다. 이 명령어를 이용하기 위해서는 Python 을 이용해서 설치를 해줘야 하는데 letencrypt 를 git 클론하면 들어있다. 설치하고 실행을 하면 의존성 패키지가 없다는 메시지가 나오는데 함께 설치해주면 된다. 20.04 LTS, Python 3.8 에서 정상적으로 동작했다.
JAVA_OPTS 환경 변수에 user.language, region 을 정의해 주면 된다. 그러면 Tomcat 서버가 구동될때에 JAVA 파라메터로 추가해 로케일을 적용해 주면 UTF-8 에 Windows 10 에 로케일을 버리고 English 언어와 US 로케일이 적용되어 영문으로 로그가 출력된다.
Kubernetes 는 Secret 객체를 제공 한다. 이것을 이용하면 패스워드와 같은 비밀이 필요한 필드 값들을 암호화해서 저장할 수 있다. 이렇게 하는 이유는 Pod 에 배포되는 소프트웨어들은 비상태여야 하며 언제든지 Pod 는 삭제되어 질 수 있어야 하기 때문에 각종 설정에 필요한 파라메터들도 외부에서 관리되어져야 한다.
Grafana 설치를 하는데 있어 Secret 를 이용하는 이유는 Grafana 의 관리자 계정 때문이다. 아무나 Grafana를 조작하지 못하도록 계정 정책을 가지고 있는데, ID 와 패스워드를 발급해야 한다. 관리자의 경우에 ID 는 admin 이고 패스워드는 설치할때에 지정해 줄 수 있는데 이것을 Kubernetes 의 Secret 으로 등록해 Pod 가 생성될때에 적용되게 한다.
Grafana 를 Secret 생성
1
2
3
4
5
6
7
8
9
10
# vim grafana-secret.yaml
apiVersion:v1
kind:Secret
data:
admin-password:YWRtaW4=
admin-username:YWRtaW4=
metadata:
name:grafana
namespace:monitoring
type:Opaque
Secret 은 Key – Value 쌍으로 간단하게 정의할 수 있다. 다음과 같이 적용한다.
Grafana 를 Secret 생성
ZSH
1
2
$kubectl apply-fgrafana-secret.yaml
secret/grafana created
Grafana Deployment
PV, Secret 을 생성했다면 이제 Deployment 를 만들어 Pod 를 생성해보자. Deployment 에는 Secret, PV 를 적용시켜야 한다.
Grafana 를 Deployment 생성
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# vim grafana-deployment.yaml
apiVersion:apps/v1
kind:Deployment
metadata:
name:grafana
namespace:monitoring
labels:
app:grafana
spec:
replicas:1
selector:
matchLabels:
app:grafana
template:
metadata:
name:grafana
labels:
app:grafana
spec:
containers:
-name:grafana
image:grafana/grafana:latest
imagePullPolicy:IfNotPresent
ports:
-name:grafana
containerPort:3000
env:
-name:GF_AUTH_BASIC_ENABLED
value:"true"
-name:GF_SECURITY_ADMIN_USER
valueFrom:
secretKeyRef:
name:grafana
key:admin-username
-name:GF_SECURITY_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name:grafana
key:admin-password
-name:GF_AUTH_ANONYMOUS_ENABLED
value:"false"
readinessProbe:
httpGet:
path:/
port:3000
volumeMounts:
-name:grafana-persistent-storage
mountPath:/var/lib/grafana
nodeSelector:
kubernetes.io/hostname:knode
volumes:
-name:grafana-persistent-storage
persistentVolumeClaim:
claimName:grafana-pvc
nodeSelector 를 이용해 knode 에 생성하도록 했다. 앞에서 생성한 PVC 를 사용하도록 했으며 secretKeyRef 를 이용해 Grafana 의 변수에 Secret 에 초기 아이디, 패스워드를 지정해주고 있다.
다음과 같이 적용해 준다.
Grafana 를 Deployment 생성
ZSH
1
2
$kubectl apply-fgrafana-deployment.yaml
deployment.apps/grafana created
NodePort 서비스 생성
Grafana 가 제대로 설치되었는지를 확인하기 위해서 외부에서 접속이 되도록 NodePort 로 Service 를 생성해 보자.
Grafana 를 Service 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# vim grafana-service.yaml
apiVersion:v1
kind:Service
metadata:
name:grafana
namespace:monitoring
annotations:
prometheus.io/scrape:'true'
prometheus.io/port:'3000'
spec:
selector:
app:grafana
type:NodePort
ports:
-port:3000
targetPort:3000
nodePort:30004
Service 에 대한 포트는 3000 이며 Pod 에 포트도 3000 이여서 targetPort 를 3000 으로 지정했다. 그리고 nodePort 를 30004 으로 지정했다.
이렇게 하면 Kmaster 서버의 IP:30004 로 웹 접속을 하면 Grafana 화면이 보여야 한다.
Grafana 에서 Prometheus 데이터소스 추가
Grafana 와 Prometheus 는 Kubernetes 상에서 작동되고 있다. Kubernetes 에서 서비스에 접속을 하기 위해서는 Service 객체에 등록해 IP와 Port를 할당하면 Kubernetes Cluster 내에서는 Service 객체에 등록한 IP:Port 로 접속이 가능하다.
Grafana 에 성공적으로 접속을 했다면 TimeSeries 데이터소스를 추가해줘야 한다. Prometheus 를 지원하고 있기 때문에 접속 URL 을 입력해줘야 하는데, 이때 Prometheus 가 Kubernetes 상에서 작동되고 있다는 것을 상기해야 하며 Service 객체에 등록되어 Cluster IP:Port 를 입력해 줘야 한다.
이 글은 Kubernetes 에 모니터링을 위해 Prometheus 설치에 대한 것이다. Kubernetes 는 여러가지 오브젝트들과 컴포넌트들로 구성 된다. 각각에 구성요소들은 컴퓨터의 자원을 사용하게 되는데 이러한 자원 사용량은 metric-server 를 설치함으로써 CLI 를 통해서 실시간으로 모니터링이 가능하다.
하지만 CLI 를 하나하나 다 치면서 하는데에는 한계가 있어, 각종 구성요소들의 자원 사용량을 데이터베이스로 저장하고 이것을 기반으로 그래프로 보여주는 것이 훨씬 좋을 것이다. 특히나 각종 자원의 모니터링은 시인성이 아주 좋아야 하는게 핵심이기도 한데 Kubernetes 는 이를 위해서 Prometheus 를 공식적(?) 으로 밀고 있다.
Prometheus
프로메테우스(Prometheus) 는 한 회사에서 만들기 시작해 오픈소스화 되었으며 현재는 Kubernetes 를 제작지원하는 CNCF(Cloud Native Computing Foundation) 의 두번째 프로젝트다. 이렇게 되면 당연히 Kubernetes 에서 Prometheus 는 거의 표준 모니터링 시스템이라고 봐야 한다.
인터넷을 검색해보면 위와같은 그림을 볼 수 있는데, 처음 접하는 사람들은 당연히 이게 뭔지 잘 모른다. Prometheus 를 이루는 기본 요소는 단 두개다.
Prometheus Server
Node Exporter
간단하게 Server/Client 구조를 가지는 것인데, 특이한 것은 Prometheus Server 가 데이터를 가지고 오는 방법이다. Node Exporter 는 어떤 정보를 수집할지에 대해서 정의를 해두고 정해진 시간마다 정보를 수집한다. 그리고네트워크를 통해서 Prometheus Server 가 가지고 갈 수 있도록 네트워크 데몬으로 존재한다.
Prometheus Server 는 Node Exporter 목록을 가지고 있으면서 주기적으로 접속해서 데이터를 긁어온다. 이렇게 긁어온 데이터는 Prometheus 가 TimeSeries 데이터베이스로 저장하게 된다.
위 그림에 왼쪽 아래쪽에 KUBERNETES NODES 로 향하는 화살표에 Pull 이라고 적혀있는데, 이것이 Prometheus 가 Node Exporter 에 접속해 데이터를 긁어오는 것을 말하는 것이다.
metric-server, metric-state-server
Kubernetes 는 자신의 상태를 자동으로 모니터링해서 보여주지 않는다. 이것도 관리자가 설치해야 한다. 이를 위해서 인터넷을 검색해보면 다음과 같이 두가지 정도가 나온다.
metric-server
kube-state-metrics
metric-server 는 Kubernetes 자신에 대한 자원 모니터링으로 Node, Pod 등의 자원을 모니터링 한다. 이것은 Resource Metrics API 를 구현한 것으로 보면 된다. 이를 설치하면 HPA(Horizontal Pod Autoscaler), Scheduler 등에서 활용하게 된다.
HPA, Scheduler 등은 실시간으로 CPU, Memory 등에 변화를 감지해야 하며 이를 통해서 액션을 취해야하기 때문에 Kubernetes 의 Health 상태도 더블어 체크 된다. 자원이 Health 상태가 되지 않는다면 Kubernetes 의 상태를 Unknown 으로 바꾸놓을 가능성이 있다. 그리고 이 상태가 지속되면 Terminated 시켜버리고 다른 오브젝트를 올릴려고 할 것이다.
문제는 Prometheus 에서 이들에 대해서 스크랩을 할 수 없다는데 있다.
kube-state-metrics 는 Kubernetes 자원의 Health 상태를 전혀 고려하지 않는다. 그냥 자원에 대한 정보를 뿌려줄뿐이고 어떤 원인으로 인해서 자원 모니터링이 안된다면 그냥 정보를 안 뿌려준다. 따라서 이렇게 되며 이것을 가지고 HPA, Scheduler 에서 사용하기가 불가능해진다.
대신, kube-state-metrics 는 Prometheus 에서 스크랩이 가능하다. 따라서 Prometheus 를 이용한 모니터링을 구축하기 위해서는 반드시 kube-state-metrics 를 설치해주는 걸 권장한다.
kube-state-metrics 설치
Prometheus 설치의 시작은 kube-state-metrics 설치로부터 시작 된다. 이것이 없으면 Prometheus 설치/운영을 못하는 것은 아니지만 Kubernetes 의 컴포넌트의 자세한 정보를 가지고 올 수 없다.
먼저 Prometheus 설치하는 방법에는 다양한 방법이 존재한다. helm 을 이용해도 되고 Prometheus Operator 를 이용해도 된다. 하지만 수동으로 설치를 해봐야 Kubernetes 에서 프로그램 배포를 위해서 필요한 것들이 무엇인지를 알게 된다. 따라서 여기서는 모든걸 수동으로 한번 해보도록 하겠다.
계획
일단, 계획이 필요한데 뭔가 대단한게 아니라 Prometheus 를 운영하는데 필요한 설정과 파일들을 어떻게 할 것인가에 대한 것이다.
먼저, Prometheus 를 위한 네임스페이스를 별도로 만든다. Kubernetes 는 네임스페이스 개념이 존재한다. 일종의 격리되는 그룹같은 것인데, Prometheus 를 위한 네임스페이스로 montoring 을 만들 것이다.
Prometheus 는 설정 파일과 데이터 저장 파일 크게 두가지로 나뉜다. 설정 파일은 그야말로 메트릭 수집과 운영에 대한 것으로 text 파일이며 데이터 저장 파일은 수집된 정보를 저장하는 TimeSeries 데이터 파일이다.
prometheus.yaml
tdb
Kubernetes 는 배포되는 프로그램의 각종 설정들을 pod 자체에 가지고 있게 하지 않는다. 이것은 pod 가 비상태 운영을 기본원칙으로 하기 때문이다. pod 는 언제든지 사라지고 만들어지고 해야 한다. pod 내에 배포되는 프로그램들의 설정파일을 pod 에 내장하게 되면 뭐하나 바꿀때마다 pod 를 손대야 한다.
ConfigMap 은 이렇게 Kubernetes 의 비상태 운영 원칙을 위한 것이다. 설정 맵은 그야말로 다양한 설정들의 내용을 Kubernetes 가 대신 가지고 있게 해준다. 예를들어 Prometheus 의 설정파일인 prometheus.yaml 은 text 파일인데, 이것을 ConfigMap 에 등록하고 Pod 생성시에 이것을 가지고와서 파일로 굽게 된다. 설정파일을 Kubernetest 가 가지고 있기 때문에 설정 편집을 위해서 pod 에 손을 댈 일은 없다.
데이터 저장 파일은 영구적인 저장 파일이다. Pod 에 내장되어 있다면 Pod 가 재시작될때마다 데이터 저장 파일은 삭제되었다 재 생성되는 과정을 반복할 것이다. 하지만 Pod 의 재시작과는 상관없이 데이터는 영구적으로 보존 되어야 하기 때문에 Pod 에 영구볼륨(Persistant Volume) 을 붙여서 데이터 저장 파일을 Pod 와 분리할 것이다.
추가로 Prometheus 나 exporter 들이 Kubernetes 의 API 에 접근할 수 있도록 계정과 권한도 부여할 것이다.
monitoring 네임스페이스 생성
Kubernetes 의 네임스페이스 생성은 아주 간단다. CLI 명령어로 간단하게 생성할 수 있다.
namespace 생성
ZSH
1
2
$kubectl create ns monitoring
namespace/monitoring created
ClusterRole 생성
Kubernetes 의 자원에 대한 접근은 API 를 통해서 이루어 진다. API 접근은 Kubernetes 의 보안 부분으로 엄격하게 통제되고 있는데, Prometheus 가 이 API 에 접근해 자원에 대한 메트릭을 생성해야 하기 때문에 이에 대한 접근 권한이 필요하게 된다.
Kubernetes 의 API 에 대한 권한은 Role 개념으로 정립되어 있으며 이 Role 에 기반한 퍼미션을 부여하고 이것을 다시 특정한 계정과 바인딩 함으로써 접근제어는 마무리 된다.
Prometheus 를 위한 Role 과 Binding
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
40
41
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"]
---
apiVersion:v1
kind:ServiceAccount
metadata:
name:prometheus
namespace:monitoring
---
apiVersion:rbac.authorization.k8s.io/v1
kind:ClusterRoleBinding
metadata:
name:prometheus
namespace:monitoring
roleRef:
apiGroup:rbac.authorization.k8s.io
kind:ClusterRole
name:prometheus
subjects:
-kind:ServiceAccount
name:prometheus
namespace:monitoring
위와같이 ClusterRole 을 작성한 후에 적용해 준다.
ClusterRole 적용
ZSH
1
2
3
$kubectl apply-fprometheus-cluster-role.yaml
clusterrole.rbac.authorization.k8s.io/prometheus created
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
Prometheus 를 위한 영구볼륨 생성
Kubernetes 에서 영구 볼륨은 Persistant Volume 과 Claim 개념으로 다루어 진다. PV 는 영구저장소 미디어 특성을 고려한 일종의 드라이버 개념이고 Claim 은 영구저장소 미디어와는 상관없는 추상적 개층으로 PV 와 연결되어 작동된다.
Prometheus 는 데이터베이스 파일을 영구적으로 저장할 필요성이 있기 때문에 Kubernetes 의 PV, PVC 를 이용할 필요가 있다.
먼저 다음과 같이 PV 를 만든다.
Prometheus 를 위한 PV
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:PersistentVolume
metadata:
name:prometheus-pv
namespace:monitoring
labels:
type:local
app:prometheus
spec:
capacity:
storage:2Gi
accessModes:
-ReadWriteOnce
persistentVolumeReclaimPolicy:Retain
storageClassName:manual
hostPath:
path:/opt/prometheus
type:DirectoryOrCreate
nodeAffinity:
required:
nodeSelectorTerms:
-matchExpressions:
-key:kubernetes.io/hostname
operator:In
values:
-knode
중요한 것은 영구저장소를 이용할 Kubernetes 의 Node 를 지정해 주었고, 사용할 저장소는 디렉토리이며 없으면 생성하도록 했다. 거기다 ReclaimPolicy 를 Retain 으로 함으로써 PVC 와 연결이 해제되더라도 PV 는 그대로 데이터를 보존하도록 했다. 사용할 디렉토리 경로는 /opt/prometheus 로 지정 했다.
다음과 같이 생성해 준다.
Prometheus 를 위한 PV 생성
ZSH
1
2
3
4
5
$kubectl apply-fprometheus-pv.yaml
persistentvolume/prometheus-pv created
$kubectl get pv-nmonitoring
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
prometheus-pv2GiRWO Retain Available manual64s
이제 PV 를 가져다 쓸 PVC 를 생성해야 한다.
Prometheus 를 위한 PVC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion:v1
kind:PersistentVolumeClaim
metadata:
name:prometheus-pvc
namespace:monitoring
labels:
type:local
app:prometheus
spec:
storageClassName:manual
accessModes:
-ReadWriteOnce
volumeMode:Filesystem
resources:
requests:
storage:1Gi
selector:
matchLabels:
app:prometheus
type:local
PVC 를 생성할 때에는 PV 에서 가져다 쓸 용량도 함께 기재한다. 당연한 이야기지만 PV 보다 많은 용량은 허용되지 않는다. 한가지 주의해야 할 것은 PV 의 Label 과 StorageClass 를 맞춰야 한다. 이게 어긋날 경우에는 PVC 가 제대로 연결되지 않는다.
다음과 같이 생성해 준다.
Prometheus 를 위한 PVC 생성
ZSH
1
2
3
4
5
6
7
8
$kubectl apply-fprometheus-pvc.yaml
persistentvolumeclaim/prometheus-pvc created
$kubectl get pv,pvc-nmonitoring
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
앞에서도 이야기 했지만, Kubernetes 에서 Pod 는 비상태여야 한다. Pod 는 Replica 정책에 의해서 항상 특정한 수를 유지하도록 하는데, 간혹 Pod 가 알수 없는 이유로 재생성되는 경우가 발생하는데 이럴때에 Pod 가 상태를 가지는 파일을 가지고 있게 되면 데이터 손실이 발생하게 된다.
그래서 각종 서버에 대한 설정파일들을 Kubernetes 에 ConfigMap 으로 등록하고 Pod가 생성될때에 이를 가져다 설정파일로 만들도록 권장하고 있다.
ConfigMap 을 만드는 방법에는 크게 두가지로 나뉜다. 첫번째는 ConfigMap 메니페스트 파일에 설정 내용을 모두 함께 기술하는 것과 서버 설정파일을 특정한 디렉토리에 만든 다음에 kubectl 명령어로 ConfigMap 을 만드는 것이다. 어떤 방법을 쓰던지 결과는 동일하다.
여기선 설정 파일을 특정 디렉토리 별도로 만들어서 kubectl 명령어를 이용해 ConfigMap 을 작성하는 것으로 한다.
Prometheus 를 위한 설정 파일은 prometheus.yml 파일이다. 단 하나의 파일로 모두 가능하지만 rules 같은 경우에는 별도의 파일로 작성해 include 문을 작성해 연결 시킬 수 있다. 여기서는 두개의 파일로 제작했다.
prometheus.yml 파일의 내용을 보면 어떤 정보를 수집할지에 대해서 기술하고 있다. 전체적으로 10s 단위로 메트릭 정보를 수집하도록 하고 있으며 kube-state-metrics 에 대해서는 도메인 호출을해서 스크랩을 하도록 하고 있다. 그밖에 각종 Kubernetes 컴포넌트들에 대해서도 Kubernetes 의 API 서버를 통해서 메트릭을 수집하도록 설정하고 있다.
이렇게 설정내용을 파일로 작성하였다면 kubectl 명령어를 이용해 ConfigMap 을 다음과 같이 생성할 수 있다.
이제 필요한 제반 사항들은 모두 만들어 졌다. 실제 Prometheus 배포로 Pod 를 생성해 보자.
Prometheus 를 위한 Deployment
Kubernetes 가 버전이 높아지면 Deployment 를 기반으로 여러개의 Pod 를 생성하도록 변경되었다. 여기서는 Prometheus 를 만들어야 하는데, 단순하게 Pod 만 생성하는게 아니라 Deployment 를 이용해서 Pod 를 생성 한다.
Prometheus 를 위한 Deployment
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
40
41
42
apiVersion:apps/v1
kind:Deployment
metadata:
name:prometheus-deployment
namespace:monitoring
labels:
app:prometheus-server
spec:
replicas:1
selector:
matchLabels:
app:prometheus-server
template:
metadata:
labels:
app:prometheus-server
spec:
serviceAccountName:prometheus
containers:
-name:prometheus
image:prom/prometheus
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/
nodeSelector:
kubernetes.io/hostname:knode
volumes:
-name:prometheus-config-volume
configMap:
defaultMode:420
name:prometheus-config
-name:prometheus-storage-volume
persistentVolumeClaim:
claimName:prometheus-pvc
지금까지 만들었던 제반사항들이 모두 포함되어 있다. ServiceAccount 의 경우에는 Deployment.spec.serviceAccountName 에 prometheus 로 지정해 ClusterBinding 으로 묶인 메트릭 수집을 위한 API 접근을 부여하고 있다. Volume 마운트 에서는 ConfigMap 을 마운트해 파일을 작성과 PVC 를 마운트해 Prometheus 의 데이터 저장 디렉토리로 마운트 해주고 있다.
“permission denied” 이 에러는 PV 에서 생성한 /opt/prometheus 디렉토리에 대한 권한이 없어서 나는 것이다. PV 를 생성한 Node 에 다음과 같이 퍼미션을 부여 한다.
/opt/prometheus 디렉토리 퍼미션 조정
ZSH
1
# chmod 757 /opt/prometheus
위와같이 퍼미션을 조정해 주면 자동으로 Pod 가 재배포 되면서 정상화 된다.
접속을 위한 Service 배포
Kubernetes 는 기본적으로 Cluster 내에서의 접속만 허용 한다. 외부에서 접속이 되게 하기 위해서는 Service 배포를 통해서 NodPort 를 열거나 아니면 Port-Forward 를 설정을 해서 접속을 해야 한다.
여기선 Service 배포를 통해서 NodePort 를 배포해 준다.
Service 배포를 통한 NodePort 오픈
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$vim prometheus-service.yml
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
Deployment 에서 Container 포트를 9090 으로 해줬다. Service 에서는 targetPort 로 Container 포트를 인식시켜주고 Service 에서 사용할 포트 8080 과 연결해준다. Cluster 내에서 8080 포트로 접속을 하면 Deployment 의 Container 에 9090 와 연결되어 응답이 오게 된다.
nodePort 를 지정해줘서 외부에서도 접속할 수 있도록 오픈해 준다.
다음과 같이 배포를 진행 한다.
Service 배포
ZSH
1
2
$kubectl apply-fprometheus-service.yaml
service/prometheus-service created
Node Exportor
Node Exportor 는 Kubernetes 의 Node 에 대한 정보를 수집해 준다. Kubernetes 는 모든 것을 Pod 로 작동되는데, Node 에 하나씩만 작동되어야 하며 Kubernetes 클러스터와는 별도로 Node 자체에 데몬(Daemon) 처럼 동작해야 한다. 이를 위해서 DaemonSet 오브젝트로 만들어야 한다.
DeamonSet 내용
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
40
41
$vim 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
---
apiVersion:v1
kind:Service
metadata:
labels:
k8s-app:node-exporter
name:node-exporter
namespace:kube-system
spec:
ports:
-name:http
port:9100
nodePort:31672
protocol:TCP
type:NodePort
selector:
k8s-app:node-exporter
위 내용을 배포하게 되면 Node Exportor 가 DaemonSet 으로 동작한다. 그리고 Prometheus 는 정해진 시간마다 Node Exportor 에 접속해 메트릭을 수집하고 저장하게 된다.
마치며
Prometheus 는 Kubernetes 와 잘 작동 한다. Kubernetes 를 하면서 다양한 방법으로 설치를 진행할 수 있는데, 한번 쯤은 수동으로 모두 해보는 것을 권장하고 한번 공부해보길 권장한다. 그것만으로도 Kubernetes 에 대해서 상당히 많은 부분을 익힐 수가 있다.
Kubernetes 는 다양한 컴포넌트들로 인해서 작동된다. 이러한 컴포넌트들은 중요성에 있어서 약간의 차이가 있다. 예를들어 Worker Node 에서 docker 프로세스가 정지되거나 문제가 되었을때에 어떻게 될까? 혹은 Worker Node 에 kubelet 프로세스가 문제가 된다면?
이 문서는 Kubernetes 프로세스별 상태 에 대한 글이다.
환경
여기서 환경은 Kubernetes 의 객체를 말한다. 객체라함은 Pods, Deployments, Services, StatefulSet 으로 했다. 그밖에 다양한 객체가 있지만 이 정도 생성해서 진행해보기로 했다.
docker 정지
이것은 Work Node 에 docker 를 정지 시키는 것이다. 이렇게 되었을때에 Kubernetes 의 각종 컴포넌트들은 어떤 상태를 보일지 알아보자.
먼저, Nodes 상태는 ‘Notready’ 로 변경된다.
Node 상태
ZSH
1
2
3
4
kubectl get nodes
NAME STATUS ROLES AGE VERSION
kmaster Ready master16dv1.18.6
knode NotReady<none>15dv1.18.6
Node 의 자세한 상태를 describe 보면 다음과같이 몇가지 상태가 나온다.
Warning ContainerGCFailed 38s (x2 over 98s) kubelet, knode rpc error: code = Unknown desc = Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Conditions 는 다음과 같이 된다.
Node Condition 상태
1
2
3
4
5
6
7
8
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message