티스토리 뷰
이번 글은 개인 프로젝트를 진행하다가 생긴 문제를 트러블 슈팅하는 전반적인 흐름을 담고 있습니다.
다소 맥락이 어지러우실 수 있습니다😅
문제 상황
쿠버네티스 클러스터 내에 Nexus Repository를 구축하여 Image 저장소로 사용.
기존 모든 컴포넌트는 http 통신을 사용하고 있었으나, Pulling시 default로 https를 사용하여 파드가 생성되지 않음.
Docker의 insecure-registry 설정처럼 Containerd를 조작할 수 있겠지만, SSL를 붙여보기로 결정.
nginx ingress controller는 nginx의 거의 모든 기능을 지원하는 것으로 알고 있으므로, 이를 통해 리버스 프록시를 사용하기로 함.
NGINX Controller
인그레스는 클러스터 외부에서 클러스터 내부 서비스로 HTTP와 HTTPS 경로를 노출한다. 트래픽 라우팅은 인그레스 리소스에 정의된 규칙에 의해 컨트롤된다. 이러한 인그레스는 라우팅 규칙만을 정의하는 리소스라고 이해하는 것이 편하고, 실제 동작을 실행하는 구현체는 인그레스 컨트롤러이다.
ingress-nginx는 NGINX 를 리버스 프록시 및 로드 밸런서로 사용하는 Kubernetes용 Ingress 컨트롤러이다.
매니페스트를 이용해 직접 설치하거나 Helm을 사용할 수 있다.
설치
nginx ingress controller의 설치는 어렵지 않다.
helm과 매니페스트를 통한 배포를 지원하며, 해당 내용은 공식 문서를 확인할 수 있다.
kubernetes 진영에서 관리하는 nginx ingress controller가 있고,
nginx 진영에서 관리하는 nginx ingress controller가 있다.
kubernetes 공식 문서에서 진행하는 example은 당연히 kubernetes 진영이다.
또 다양한 환경에 따른 배포판을 사용한다.
나는 GCP에서 k8s를 직접 구축하여서 베어메탈로 진행했어야 하는데 GCE-GKE의 배포판을 사용해서 동작에 장애가 있었다.
K8S의 인증서 관리
쿠버네티스 환경에서 인증서 관리를 위한 Cert-manager 라는 오픈 소스가 존재한다.
Cert-Manager는 클러스터에서 SSL/TLS 인증서의 발급, 갱신 및 관리를 관리하고 자동화하기 위한 Kubernetes 네이티브 솔루션이다.
다양한 CA(인증 기관)에서 인증서를 취득, 갱신 및 관리하는 프로세스를 자동화할 수 있는 방법을 제공한다.
cert-manager를 사용하면 애플리케이션과 서비스가 항상 최신의 유효한 인증서를 수동으로 사용하지 않고 사용할 수 있다.
또한 설치도 간편하게 진행할 수 있다.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml
Let's Encrypt
인증서를 발급 받으려면 공신력 있는 CA(Certificate Authorities)의 인증이 필요한데, 실제로 이러한 기관을 통해 인증서를 발급받으려면 비용이 발생한다.
하지만 Let’s Encrypt를 통해 SSL 인증서를 무료로 발급받을 수 있다.
Cert-Manager는 Let 's Encrypt와 통합되어 Kubernetes 클러스터 내에서 SSL/TLS 인증서를 획득, 갱신 및 관리할 수 있다.
Let's Encrypt는 자동화 프로세스의 한계가 있어, 도메인 유효성 검사 방식의 인증만이 가능하다.
- 도메인 인증 방식
- DV(Domain Validation): 도메인 유효성 검사
도메인 소유권 심사를 통해 발급되는 가장 쉽고 빠른 인증서, 회사에 대한 정보 확인 불가능 - OV(Organization Validation) : 조직 유효성 검사
비즈니스 적법성 검증과 도메인 소유권 심사를 통해 발급, 검증된 회사 정보는 인증서에 표기됨 - EV(Extended Validation) : 확장 유효성 검사 DV,OV보다 까다로운 검증을 통해 기업의 실존성을 인증. EV인증서를 소유한 사이트는 브라우저에서 도메인 소유 회사의 이름이 표시되어 안전한 사이트임을 확인할 수 있음
- DV(Domain Validation): 도메인 유효성 검사
이러한 인증서를 발급 받기 위해서는 반드시 IP가 아닌 도메인이 필요하다.
Let's Encrypt의 인증 방식은 간단히 설명하자면 인증서 요청을 받으면,
해당 도메인에 도메인 유효성 검증을 위해 해당 도메인에게 챌린지를 부여하고 이 후에 인증서를 발급 해 준다.
K8S에서 인증서 생성 트러블 슈팅
Cert-manager를 통해 인증서를 발급해 내 애플리케이션에 https를 적용하려고 하는데 문제가 발생했다.
위 과정은 공식 문서를 통해 간단하게 따라할 수 있다.
문제 인식
위 예제와 많은 구글링을 통해 잘 적용했다고 생각했는데 Fake Certificate가 발급되어 SSL이 제대로 동작하지 않았다.
인증서 발급 과정에서 문제가 있었던 것으로 생각해서 로그를 뒤졌다.
cert-manager webhook 파드와 cert-manager 파드에서 해당 에러를 찾을 수 있었고, SSL 핸드쉐이크 과정에서 문제가 있을 것 이라고 생각했다.
공식 문서를 통해 트러블 슈팅을 따라가다 보니 챌린지 과정해서 내 도메인의 80포트로 접근할 수 없다는 것이었다. (로그를 저장안해서 잃어버림..)
문제 해결?
GCP에서 구성된 내 클러스터는 아무런 GCP 서비스를 사용하지 않으니 사실상 베어메탈이어서, 인그레스 컨트롤러도 노드포트를 사용하고 있었다.
로드밸런서 타입을 사용하지 않아 nginx를 80포트로 제공할 수 없는 것이 문제였다.
내가 생각한 솔루션으로는 크게 4가지 정도가 떠올랐다.
- 인그레스 컨트롤러를 로드밸런서 타입으로 변경
- GKE로 이전
- Cloud Load Balancing 서비스 사용
- Nexus 자체 TLS 적용
- nginx를 데몬으로 띄워서 리버스 프록시 사용
이 중에 내가 선택한 것은 3번이다.
1-1의 경우 애초에 베어메탈로 구성한 이유가 마스터 노드를 나의 관리 하에 두고자 하는 것이었기에 배제하였고,
1-2의 경우 로드밸런서 서비스를 적용하기 위해 변경 사항이 너무 커질 것 같았다. 이제 곧 카카오클라우드스쿨의 최종 프로젝트가 시작될 것이라 개인 프로젝트를 위한 시간이 얼마 남지 않았다.
2번의 경우 꽤나 괜찮은 선택지일 것이다.
하지만 nginx를 기능적으로 공부해 본적이 없어서, 리버스 프록시 기능을 사용해 보고 싶은 마음이 컸다.
(도메인도 샀기 때문에..)
NGINX 리버스 프록시
그리하여 nginx를 데몬으로 띄우고 리버스 프록시를 설정하고,
SSL 인증을 위해 Let's Encrpty을 사용하기 위해, certbot을 사용한다.
NGINX 설정
nginx를 운영체제에 맞게 설치하고 /etc/nginx/conf.d
에 default.conf
파일을 생성한다.
이 파일 안에 리버스 프록시를 통해 포워딩 될 서버의 정보를 넣어줘야 하는데, nexus 공식 문서에서 nginx 혹은 Apache httpd를 위한 예제를 제공 한다.
server {
listen 80;
server_name jacapa.cloud; # 나의 도메인
location / {
proxy_pass http:{server ip};
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
}
}
최소한의 설정을 해주고 저장한다.
Certbot
Certbot은 우분투의 snap 이라는 패키지 매니저를 사용하여 설치하는 것이 권장된다.
따라서 apt가 아닌 snap을 사용하여 설치하고 인증서를 발급 한다.
sudo snap install certbot --classic
sudo certbot --nginx
이메일을 입력하고, 이용약관에 동의 후 사용할 도메인을 입력하는 과정을 거치면 된다.
나는 생략 했지만 각자의 환경에 맞게 적용할 도메인에 대한 A 레코드가 반드시 적용되어 있어야 한다.
이 과정을 거치면 Certbot은 Let's Encrypt를 통해 자동으로 SSL 인증서를 발급해온다.
그리고 /etc/nginx/con.f/default.conf
를 다시 확인해보면 Certbot이 https를 위한 설정을 추가해주었음을 확인할 수 있다.
server {
server_name jacapa.cloud;
location / {
proxy_pass http://{server ip};
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/jacapa.cloud/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/jacapa.cloud/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = jacapa.cloud) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name jacapa.cloud;
return 404; # managed by Certbot
}
마무리
이러한 과정을 통해 소기 목적을 달성할 수 있었다.
하지만 프록시를 통해 이미지 파일을 업로드하고 다운로드하기 때문에 체감상 많은 속도 저하가 느껴졌어서 실제 서비스에서 실효성있는 방식인지 고민해봐야 할 것 같다.
1-2 선택지의 경우 이제까지 devops 팀을 가지고 있는 회사들이 왜 많은 비용을 내며 CSP의 쿠버네티스 서비스를 사용하는지 이해하지 못했었다.
하지만 로드밸런서를 직접 생성해서 붙였을 때 추후 유지보수 등에서 생겨날 과정들을 생각하니 쿠버네티스 서비스가 얼마나 강력한지 대략적으로 알 것 같았다.