2. ArgoCD 구축 (2) ArgoCD 에 HTTP 허용
- Security Rule 수정
- 80 포트 nodeport 생성 (service.yml 작성 → apply)
- 80 포트 Rule 이 적용된 Security Rule Id를 명시한 ingress 생성 (ingress.yml 작성 → apply)
argocd-server 파드의 경우 기본적으로 HTTP 요청 수신 시에는 HTTPS로 Redirect 되게끔 설정되어 있다. 현재 실습에서는 ArgoCD 서버에 80 포트를 허용하는 실습으로 진행하기로 했다. HTTPS 를 허용하려면 인증서를 발급받아야 하는데, 인프라 레벨에서 인증서를 등록하려면 비용문제도 있고, 개발 스터디 버전으로 인증서를 발급받아서 사용할 필요 까지는 없기 때문.
혹시 만약 https 를 허용하려면 ALB가 AWS ACM 을 통해 SSL 인증서 동작을 처리하고 백엔드 애플리케이션으로는 HTTP 트래픽을 전달하게끔 해주면 된다.
ArgoCD Deployment 내의 args에 --insecure 옵션 추가 후 재배포
deployment 중 argocd-server
에 대해 아래의 JSON 옵션을 적용해서 patch 해준다.
그리고 deployment 를 통해 배포된 pod 들이 실제로 재배포 되었는지 AGE
를 통해 체크한다.
[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/args",
"value": ["/usr/local/bin/argocd-server", "--insecure"]
}
]
위의 JSON 은 jsoneditoronline.org (opens in a new tab) 을 이용해서 인라인 문자열로 변환해서 CLI 명령에 인자값으로 전달해줬다.
실제 실습과정은 아래와 같다.
## 네임스페이스 'argocd' 내에 deployment 가 어떤 것들이 있는지 조회
$ kubectl get deployment -n argocd
NAME READY UP-TO-DATE AVAILABLE AGE
argocd-applicationset-controller 1/1 1 1 62m
argocd-dex-server 1/1 1 1 62m
argocd-notifications-controller 1/1 1 1 62m
argocd-redis 1/1 1 1 62m
argocd-repo-server 1/1 1 1 62m
argocd-server 1/1 1 1 62m
## --insecure 옵션을 붙여서 argocd-server deployment 를 patch 하기
$ kubectl -n argocd patch deployment argocd-server --type json -p='[{"op":"replace","path":"/spec/template/spec/containers/0/args","value":["/usr/local/bin/argocd-server","--insecure"]}]'
deployment.apps/argocd-server patched
## 실제로 pod 이 재배포 되었는지 확인
## 37초 전에 재배포 되었음을 확인 가능
## (이 글을 쓸때 잠깐 다른 것을 하다가 아래 명령을 내려서 37초 전이라고 표시되었다.)
$ kubectl get po -n argocd
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 70m
argocd-applicationset-controller-dc5c4c965-qrz7m 1/1 Running 0 70m
argocd-dex-server-9769d6499-tl5jd 1/1 Running 0 70m
argocd-notifications-controller-db4f975f8-dhcqj 1/1 Running 0 70m
argocd-redis-b5d6bf5f5-d75xc 1/1 Running 0 70m
argocd-repo-server-579cdc7849-6htrl 1/1 Running 0 70m
argocd-server-5b59f8cc5c-pnd9q 1/1 Running 0 37s
## 배포된 deployment 인 'argocd-server' 의 실제 옵션을 확인해본다.
$ kubectl -n argocd describe deployment argocd-server
## 또는 단축어인 deploy 라는 리소스명으로 확인하는 것 역시 가능하다.
$ kubectl -n argocd describe deploy argocd-server
Name: argocd-server
Namespace: argocd
CreationTimestamp: Mon, 25 Dec 2023 04:18:06 +0000
Labels: app.kubernetes.io/component=server
app.kubernetes.io/name=argocd-server
app.kubernetes.io/part-of=argocd
Annotations: deployment.kubernetes.io/revision: 2
Selector: app.kubernetes.io/name=argocd-server
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app.kubernetes.io/name=argocd-server
Service Account: argocd-server
Containers:
argocd-server:
Image: quay.io/argoproj/argocd:v2.9.3
Ports: 8080/TCP, 8083/TCP
Host Ports: 0/TCP, 0/TCP
SeccompProfile: RuntimeDefault
Args:
/usr/local/bin/argocd-server
## 실제로 이 부분을 보면 --insecure 가 적용되었음을 확인 가능하다.
--insecure
Liveness: http-get http://:8080/healthz%3Ffull=true delay=3s timeout=5s period=30s #success=1 #failure=3
Readiness: http-get http://:8080/healthz delay=3s timeout=1s period=30s #success=1 #failure=3
Environment:
ARGOCD_SERVER_INSECURE: <set to the key 'server.insecure' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_BASEHREF: <set to the key 'server.basehref' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_ROOTPATH: <set to the key 'server.rootpath' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_LOGFORMAT: <set to the key 'server.log.format' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_LOG_LEVEL: <set to the key 'server.log.level' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_REPO_SERVER: <set to the key 'repo.server' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_DEX_SERVER: <set to the key 'server.dex.server' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_DISABLE_AUTH: <set to the key 'server.disable.auth' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_ENABLE_GZIP: <set to the key 'server.enable.gzip' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS: <set to the key 'server.repo.server.timeout.seconds' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_X_FRAME_OPTIONS: <set to the key 'server.x.frame.options' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_CONTENT_SECURITY_POLICY: <set to the key 'server.content.security.policy' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_REPO_SERVER_PLAINTEXT: <set to the key 'server.repo.server.plaintext' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_REPO_SERVER_STRICT_TLS: <set to the key 'server.repo.server.strict.tls' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_DEX_SERVER_PLAINTEXT: <set to the key 'server.dex.server.plaintext' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_DEX_SERVER_STRICT_TLS: <set to the key 'server.dex.server.strict.tls' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_TLS_MIN_VERSION: <set to the key 'server.tls.minversion' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_TLS_MAX_VERSION: <set to the key 'server.tls.maxversion' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_TLS_CIPHERS: <set to the key 'server.tls.ciphers' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_CONNECTION_STATUS_CACHE_EXPIRATION: <set to the key 'server.connection.status.cache.expiration' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_OIDC_CACHE_EXPIRATION: <set to the key 'server.oidc.cache.expiration' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_LOGIN_ATTEMPTS_EXPIRATION: <set to the key 'server.login.attempts.expiration' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_STATIC_ASSETS: <set to the key 'server.staticassets' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_APP_STATE_CACHE_EXPIRATION: <set to the key 'server.app.state.cache.expiration' of config map 'argocd-cmd-params-cm'> Optional: true
REDIS_SERVER: <set to the key 'redis.server' of config map 'argocd-cmd-params-cm'> Optional: true
REDIS_COMPRESSION: <set to the key 'redis.compression' of config map 'argocd-cmd-params-cm'> Optional: true
REDISDB: <set to the key 'redis.db' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_DEFAULT_CACHE_EXPIRATION: <set to the key 'server.default.cache.expiration' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_MAX_COOKIE_NUMBER: <set to the key 'server.http.cookie.maxnumber' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_LISTEN_ADDRESS: <set to the key 'server.listen.address' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_METRICS_LISTEN_ADDRESS: <set to the key 'server.metrics.listen.address' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_OTLP_ADDRESS: <set to the key 'otlp.address' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_APPLICATION_NAMESPACES: <set to the key 'application.namespaces' of config map 'argocd-cmd-params-cm'> Optional: true
ARGOCD_SERVER_ENABLE_PROXY_EXTENSION: <set to the key 'server.enable.proxy.extension' of config map 'argocd-cmd-params-cm'> Optional: true
Mounts:
/app/config/dex/tls from argocd-dex-server-tls (rw)
/app/config/server/tls from argocd-repo-server-tls (rw)
/app/config/ssh from ssh-known-hosts (rw)
/app/config/tls from tls-certs (rw)
/home/argocd from plugins-home (rw)
/tmp from tmp (rw)
Volumes:
plugins-home:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
tmp:
Type: EmptyDir (a temporary directory that shares a pod's lifetime)
Medium:
SizeLimit: <unset>
ssh-known-hosts:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: argocd-ssh-known-hosts-cm
Optional: false
tls-certs:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: argocd-tls-certs-cm
Optional: false
argocd-repo-server-tls:
Type: Secret (a volume populated by a Secret)
SecretName: argocd-repo-server-tls
Optional: true
argocd-dex-server-tls:
Type: Secret (a volume populated by a Secret)
SecretName: argocd-dex-server-tls
Optional: true
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: argocd-server-557c4c6dff (0/0 replicas created)
NewReplicaSet: argocd-server-5b59f8cc5c (1/1 replicas created)
Events: <none>
참고) 커맨드라인에 JSON 데이터를 인라인 문자열로 변환할 때 유용한 도구
JSON 데이터를 인라인 문자열로 변환할 때 사용한 도구는 jsoneditoronline.org (opens in a new tab) 이다.
Worker Node 들이 속한 Security Rule 수정
EC2 대시보드로 이동한다. 그리고 EC2 들 중에서 eksctl 에 의해 생성된 node 들 중 하나의 체크박스를 클릭해서 세부 사항을 확인한다. 워커 노드들은 모두 같은 id 의 보안그룹(Security Group) 을 사용하고 있는 것을 확인 가능하다. 이 보안 그룹을 클릭해서 보안그룹 페이지로 넘어간다.
보안그룹 페이지에서는 인바운드 규칙 편집 버튼을 클릭해서 인바운드 규칙 편집 페이지로 이동한다.
인바운드 규칙 편집 페이지에서는 8080 포트에 대해 모든 트래픽을 허용하게끔 한다.
규칙 저장 버튼을 클릭해 규칙을 저장한다.
저장된 인바운드 규칙은 아래와 같이 확인 가능하다.
80 포트 nodeport 생성 (service.yml 작성 → apply)
argoCD에 대해 80 포트를 통해 접속을 허용하는 서비스를 정의해야 한다. 서비스(Service)란 deployment 를 통해 배포되어 있는 pod 들을 외부와 통신이 가능하도록 할 때 어떤 방식으로 노출해야 하는가를 정의하는 kubernetes 의 리소스를 의미한다.
서비스(Service) 에는 대표적으로 Ingress, Nodeport 등이 있다.
ArgoCD 설치를 통해 이미 운영중인 argocd 의 service 들은 무엇들이 있는지 확인해보자.
$ kubectl -n argocd get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.100.117.173 <none> 7000/TCP,8080/TCP 175m
argocd-dex-server ClusterIP 10.100.105.200 <none> 5556/TCP,5557/TCP,5558/TCP 175m
argocd-metrics ClusterIP 10.100.159.217 <none> 8082/TCP 175m
argocd-notifications-controller-metrics ClusterIP 10.100.149.169 <none> 9001/TCP 175m
argocd-redis ClusterIP 10.100.170.48 <none> 6379/TCP 175m
argocd-repo-server ClusterIP 10.100.139.2 <none> 8081/TCP,8084/TCP 175m
argocd-server ClusterIP 10.100.96.73 <none> 80/TCP,443/TCP 175m
argocd-server-metrics ClusterIP 10.100.29.0 <none> 8083/TCP 175m
## 또는 아래와 같이 svc 라는 단축 명령어로 확인 가능하다.
$ kubectl -n argocd get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.100.117.173 <none> 7000/TCP,8080/TCP 176m
argocd-dex-server ClusterIP 10.100.105.200 <none> 5556/TCP,5557/TCP,5558/TCP 176m
argocd-metrics ClusterIP 10.100.159.217 <none> 8082/TCP 176m
argocd-notifications-controller-metrics ClusterIP 10.100.149.169 <none> 9001/TCP 176m
argocd-redis ClusterIP 10.100.170.48 <none> 6379/TCP 176m
argocd-repo-server ClusterIP 10.100.139.2 <none> 8081/TCP,8084/TCP 176m
argocd-server ClusterIP 10.100.96.73 <none> 80/TCP,443/TCP 176m
argocd-server-metrics ClusterIP 10.100.29.0 <none> 8083/TCP 176m
이번에는 외부에서 워커노드(EC2)의 80 포트로의 유입이 발생할 경우 Pod 의 8080 포트와 연결해주는 NodePort 를 작성한다. yml 파일 명과 그 내용은 아래와 같다.
argocd-server-nodeport.yml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: argocd-server-nodeport
name: argocd-server-nodeport
namespace: argocd
spec:
ports:
- name: "80"
port: 80
targetPort: 8080
protocol: TCP
selector:
app.kubernetes.io/name: argocd-server
sessionAffinity: None
type: NodePort
워커노드의 80 포트에 대한 트래픽을 Pod 의 8080 포트에 연결해주는 NodePort 에 대한 내용이다.
그리고 이 yml 파일을 kubectl 로 적용하면 아래와 같다.
## kubectl 을 통해 적용한다.
$ kubectl apply -f argocd-server-nodeport.yml
service/argocd-server-nodeport created
## 직접 service 를 조회해보면 아래와 같이 argocd-server-nodeport 가 정상적으로 추가되었음으 확인 가능하다.
$ kubectl -n argocd get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.100.117.173 <none> 7000/TCP,8080/TCP 4h44m
argocd-dex-server ClusterIP 10.100.105.200 <none> 5556/TCP,5557/TCP,5558/TCP 4h44m
argocd-metrics ClusterIP 10.100.159.217 <none> 8082/TCP 4h44m
argocd-notifications-controller-metrics ClusterIP 10.100.149.169 <none> 9001/TCP 4h44m
argocd-redis ClusterIP 10.100.170.48 <none> 6379/TCP 4h44m
argocd-repo-server ClusterIP 10.100.139.2 <none> 8081/TCP,8084/TCP 4h44m
argocd-server ClusterIP 10.100.96.73 <none> 80/TCP,443/TCP 4h44m
argocd-server-metrics ClusterIP 10.100.29.0 <none> 8083/TCP 4h44m
argocd-server-nodeport NodePort 10.100.53.245 <none> 80:30040/TCP 4m53s
80 포트 Rule 이 적용된 Security Rule ID 를 명시한 Ingress 생성 (ingress.yml 작성 → apply)
아래 코드에 적용하는 security group, subnet 을 생성하는 과정은
- [TODO: ArgoCD ALB 용도의 Ingress 에 Subnet 지정, 보안그룹 생성] 에 따로 정리해두었다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd
namespace: argocd
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/healthcheck-path: /healthz
alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
alb.ingress.kubernetes.io/success-codes: '200'
alb.ingress.kubernetes.io/security-groups: sg-xxxxx
alb.ingress.kubernetes.io/subnets: subnet-xxxxx,subnet-xxxxx,subnet-xxxxx
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
backend:
service:
name: argocd-server-nodeport
port:
number: 80
pathType: Prefix
ALB 의 경우 외부와 통신을 통해 내부의 Nodeport 와 연결해줘야 하므로 ALB 자신은 Public 서브넷에 위치해야 한다. 이런 이유로 alb.ingress.kubernetes.io/subnets 에는 eksctl 이 생성한 Public 서브넷만 들만을 명시해줘야 한다.
작성한 ekscluster-global-ingress.yml 파일을 kubectl 을 통해 적용한다.
$ kubectl apply -f ekscluster-global-ingress.yml
ingress.networking.k8s.io/argocd created
## ingress 조회
$ kubectl -n argocd get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
argocd alb * k8s-argocd-argocd-23f933d87c-589378327.ap-northeast-2.elb.amazonaws.com 80 2m17s
## ingress 세부 내용 조회
$ kubectl -n argocd describe ingress argocd
Name: argocd
Labels: <none>
Namespace: argocd
Address: k8s-argocd-argocd-23f933d87c-589378327.ap-northeast-2.elb.amazonaws.com
Ingress Class: alb
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/ argocd-server-nodeport:80 (192.168.124.124:8080)
Annotations: alb.ingress.kubernetes.io/healthcheck-path: /healthz
alb.ingress.kubernetes.io/healthcheck-protocol: HTTP
alb.ingress.kubernetes.io/listen-ports: [{"HTTP": 80}]
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/security-groups: sg-0dfb95642ecc23d76
alb.ingress.kubernetes.io/subnets: subnet-06fe014719b653560,subnet-023fe2ec39f326241,subnet-0735aaf15bfeabec6
alb.ingress.kubernetes.io/success-codes: 200
alb.ingress.kubernetes.io/target-type: ip
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfullyReconciled 3m5s ingress Successfully reconciled
ec2 대시보드에서 로드밸런서가 잘 생성되어있는지 확인해보자.
리스너 및 규칙을 확인해보자.
맨 아래의 리스너 및 규칙 탭 → HTTP:80 링크를 클릭한다.
이동한 리스너 규칙 페이지에서는 대상 그룹으로 전달 에 해당하는 링크를 클릭한다.
이동한 페이지에서는 리스너 규칙에 해당하는 대상 그룹에서의 트래픽 현환을 확인해볼 수 있다.
밑으로 스크롤을 해보면 Healthy 라고 표시된 상태가 나타난다.
이 Healthy 라고 하는 상태는 상태검사 탭에서 볼수 있듯 /heathz 에 대해 주기적으로 체크함으로써 얻어내는 상태값이다.