AWS EKS를 이용하여 쿠버네티스 환경의 3티어 아키텍처를 구성합니다. 구성환경은 VScode를 사용합니다.
먼저, 로컬에서 kubectl 명령을 사용하기 위해 eksctl을 설치해야합니다. 아래 블로그를 참고하여 진행합니다.
이제 쿠버네티스 클러스터를 생성합니다. 아래명령을 입력하여 노드 3개를 가지고 psy라는 키페어를 이용해 ssh 접속이 가능한 클러스터를 서울 리전에 생성합니다.
eksctl.exe create cluster --name 클러스터이름 --region ap-northeast-2 --with-oidc --ssh-public-key psy --nodes 3 --node-type t3.medium --node-volume-size=20 --managed
AWS EKS에서 인그레스를 사용하기 위해 인그레스 컨트롤러를 직접 생성해야 합니다. 쿠버네티스 클러스터가 생성되면 아래 순서대로 인그레스 컨트롤러를 생성합니다.
먼저 클러스터에 대한 IAM OIDC(OpenID Connect) identity Provider를 서울리전에 생성합니다.
eksctl utils associate-iam-oidc-provider --region ap-northeast-2 --cluster 클러스터이름 --approve
AWS Load Balancer Controller에 부여할 IAM Policy를 생성하는 작업을 수행합니다.
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json
aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json
AWS Load Balancer Controller를 위한 ServiceAccount를 생성합니다. 클러스터 이름과 arn부분에 유저 id를 입력합니다.
eksctl create iamserviceaccount --cluster=클러스터이름 --namespace=kube-system --name=aws-load-balancer-controller --attach-policy-arn=arn:aws:iam::111111111111:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve
클러스터에 컨트롤러를 추가합니다. Ingress Controller를 설치하기 전에 먼저 Cert-manager를 설치합니다.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml
Load balancer controller yaml 파일을 다운로드 합니다.
curl -o v2_5_4_full.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.5.4/v2_5_4_full.yaml
v2_5_4_full.yaml 파일에 있는 ServiceAccount 섹션을 제거합니다. 아래 명령이 실행되지 않으면 직접 yaml에서 다음 부분을 제거합니다.
sed -i.bak -e '596,604d' ./v2_5_4_full.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/name: aws-load-balancer-controller
name: aws-load-balancer-controller
namespace: kube-system
---
v2_5_4_full.yaml 파일의 Deployment 섹션의 my-cluster를 현재 eks 실습에 사용되는 클러스터 이름으로 변경합니다.
아래 명령이 실행되지 않으면 직접 yaml에서 클러스터이름 부분을 입력합니다.
sed -i.bak -e 's|your-cluster-name|클러스터이름|' ./v2_5_4_full.yaml
AWS Load Balancer controller 파일을 배포합니다.
kubectl apply -f v2_5_4_full.yaml
IngressClass 및 IngressClassParams 매니페스트를 다운로드합니다. 그리고 클러스터에 매니페스트를 적용합니다.
curl -o v2_5_4_ingclass.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.5.4/v2_5_4_ingclass.yaml
kubectl apply -f v2_5_4_ingclass.yaml
컨트롤러 설치를 확인합니다.
kubectl get deployment -n kube-system aws-load-balancer-controller
클러스터 노드그룹에 EC2FullAccess 권한을 부여합니다. 노드그룹의 역할에 접속하여 권한을 추가합니다.
인그레스 컨트롤러를 설치하면 이제 RDS를 생성합니다. AWS 콘솔에서 RDS 서비스에서 데이터베이스 생성을 클릭합니다. mysql을 선택하고 엔진버전은 5.7.44 를 선택합니다.
식별자에 RDS의 이름을 입력하고 마스터 암호를 임의로 설정합니다.
연결정보에서 퍼블릭 엑세스를 허용하고 새로운 보안그룹을 생성합니다. 나머지 값을 기본으로 유지하고 데이터베이스를 생성합니다.
이제 사용하려는 데이터베이스, 유저 ,비밀번호, 테이블을 생성하고 특정 유저에게 작업을 위한 데이터베이스에 권한을 부여합니다. 데이터베이스에 로컬에서 접근하기 위해 보안그룹에서 3306포트의 인바운드 규칙을 허용해야 합니다.
로컬 터미널에서 mysql -h 데이터베이스앤드포인트 -u admin -p 명령을 이용하여 RDS에 접근합니다.
아래 명령을 입력하여 boot_board 데이터베이스를 생성합니다.
CREATE DATABASE boot_board;
아래 명령을 입력하여 유저를 생성하고 boot_board에 대한 모든 권한을 부여합니다.
CREATE USER 'suyong'@'%' IDENTIFIED BY '비밀번호';
GRANT ALL PRIVILEGES ON boot_board.* TO 'username'@'%';
FLUSH PRIVILEGES;
이후 아래 파일을 import하여 boot_board 데이터베이스에 필요한 테이블을 생성합니다.
이제 생성한 RDS에 연결되는 서비스를 생성합니다. db-svc.yaml 파일에서 externalName에 생성한 RDS의 엔드포인트를 입력합니다. 이후 apply 명령을 실행합니다.
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
spec:
ports:
- port: 3306
type: ExternalName
externalName: 데이터베이스 엔드포인트
kubectl apply -f ./db-svc.yaml
아래 명령을 통해 생성한 서비스에 외부IP 주소가 잘 연결되었는지 확인합니다.
kubectl get svc
이제 redis 파드를 생성합니다. 해당 conf파일을 이용하여 도커 이미지로 빌드하고 도커허브 저장소에 push합니다.
# Dockerfile
FROM redis
RUN mkdir /usr/local/etc/redis
COPY ./redis.conf /usr/local/etc/redis/redis.conf
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
해당 이미지를 사용하여 redis 디플로이먼트와 서비스, 컨피그맵을 생성합니다.
# Redis_conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-conf
data:
redis.conf: |
bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
daemonize no
pidfile /var/run/redis_6379.pid
loglevel notice
logfile ""
databases 16
always-show-logo no
set-proc-title yes
proc-title-template "{title} {listen-addr} {server-mode}"
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
rdb-del-sync-files no
dir ./
replica-serve-stale-data yes
replica-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-diskless-load disabled
repl-disable-tcp-nodelay no
replica-priority 100
acllog-max-len 128
requirepass suyong # 여기에 redis에서 사용할 비밀번호를 입력
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
lazyfree-lazy-user-del no
lazyfree-lazy-user-flush no
oom-score-adj no
oom-score-adj-values 0 200 800
disable-thp yes
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
jemalloc-bg-thread yes
# redis.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-svc
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: 도커이미지
volumeMounts:
- mountPath: /usr/local/etc/redis/
name: conf
imagePullPolicy: Always
ports:
- containerPort: 6379
volumes:
- name: conf
configMap:
name: redis-conf
이후 apply 명령을 실행합니다.
kubectl apply -f ./Redis_conf.yaml
kubectl apply -f ./redis.yaml
이제 스프링을 이용하여 was를 구축합니다. gradle을 통해 빌드를 하고 nginx 컨테이너로 이미지를 빌드하고 푸쉬하여 사용합니다. 아래는 속성파일 예제입니다.
# application.properties
server.port=8080
spring.main.allow-bean-definition-overriding=true
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://mysql-svc:3306/boot_board?serverTimezone=UTC
#validationQuery="select 1"
spring.datasource.hikari.username=suyong
spring.datasource.hikari.password=suyong
spring.datasource.hikari.connection-test-query=SELECT 1
#root#root
mybatis.configuration.map-underscore-to-camel-case=true
# spring.session.store-type=none
spring.session.store-type=redis
spring.redis.host=redis-svc
spring.redis.password=suyong
spring.redis.port=6379
spring.session.redis.flush-mode=on_save
spring.session.redis.namespace=spring:session
spring.thymeleaf.cache=false
spring.thymeleaf.enabled=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
아래는 도커 이미지 빌드를 위한 도커파일입니다.
FROM tomcat:9.0.52-jdk11-openjdk-buster
COPY my-spring-board-0.0.1-SNAPSHOT.war /usr/local/tomcat/webapps/ROOT.war
was 서비스와 디플로이먼트를 실행하기위한 yaml 파일입니다.
# was.yaml
apiVersion: v1
kind: Service
metadata:
name: mywas-svc
spec:
selector:
app: mywas
ports:
- port: 8080
targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mywas
spec:
selector:
matchLabels:
app: mywas
template:
metadata:
labels:
app: mywas
spec:
containers:
- name: mywas
image: 도커이미지
imagePullPolicy: Always
ports:
- containerPort: 8080
이후 apply 명령을 실행합니다.
kubectl apply -f ./was.yaml
이제 web 파드를 실행합니다. 아래는 web 파드로 접속할 때 was 파드로 리다이렉트 시키도록 nginx.conf를 구성하는 컨피그맵입니다.
# configMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
nginx.conf: |
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
upstream backend {
server mywas-svc:8080;
}
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html/;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
proxy_pass http://backend;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
}
아래는 web 파드를 실행하기 위한 디플로이먼트와 서비스입니다.
# web.yaml
apiVersion: v1
kind: Service
metadata:
name: mysvc-web
spec:
selector:
app: myweb
ports:
- port: 80
protocol: TCP
targetPort: 80
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myweb
spec:
replicas: 1
selector:
matchLabels:
app: myweb
template:
metadata:
labels:
app: myweb
spec:
containers:
- name: myweb
image: nginx
volumeMounts:
- mountPath: /etc/nginx/
name: conf
ports:
- containerPort: 80
volumes:
- name: conf
configMap:
name: nginx-conf
이후 apply 명령을 실행합니다.
kubectl apply -f ./configMap.yaml
kubectl apply -f ./web.yaml
마지막으로 Ingress를 생성합니다. 인그레스를 통해 로드밸런서가 web 파드의 서비스에 접근하도록 합니다. 인그레스를 생성하기 전에 먼저 도메인을 구매해야 합니다.
tls 설정을 위한 인증서를 생성해야 합니다. 아래 링크를 통해 도메인을 구매합니다.
가비아에서 구매한 도메인에 대해 AWS Route53의 DNS 서버를 사용하여 도메인을 찾도록 설정합니다. AWS 콘솔에서 Route53를 클릭하고 호스팅 영역을 생성합니다. 구매한 도메인을 입력하고 호스팅 영역을 생성합니다.
해당 호스팅 영역에서 아래 사진에서의 대상을 가비아에 등록해야 합니다. My 가비아에 접속합니다. 아래 네임서버 설정을 클릭하고 해당 라우팅 대상을 입력합니다.
다시 AWS 콘솔로 돌아와서 AWS Certificate Manager(ACM)에 접속합니다. 인증서 요청을 클릭하고 인그레스 yaml 파일의 호스트 부분의 도메인 이름을 아래 입력한 후 요청합니다.
아래 Route 53에서 레코드 생성을 클릭하고 생성하여 인증서 검증이 완료될때 까지 기다립니다.
아래는 아래는 인그래스를 생성하는 파일입니다. certificate-arn 부분에 인증서 arn을 입력합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myingress
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-2:111111111111:certificate/
alb.ingress.kubernetes.io/ssl-redirect: '443'
spec:
tls:
- hosts:
- www.suyong.store
secretName: tls-crt
rules:
- host: www.suyong.store
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: mysvc-web
port:
number: 80
이후 apply 명령을 실행합니다.
kubectl apply -f ./ingress.yaml
그러면 아래 명령을 통해 ingress의 ADDRESS에 로드밸런서 주소가 생성된 것을 확인할 수 있습니다.
위 주소를 Route 53에서 레코드 생성에서 www.suyong.store 의 값으로 입력하고 생성합니다.
이제 http://www.suyong.store/ 로 접속하면 https로 리다이렉트 되어 아래와 같이 화면이 표시됩니다.
'개발 > k8s' 카테고리의 다른 글
[EKS] Github Action과 ArgoCD로 CI/CD 파이프라인 구축 (0) | 2024.01.24 |
---|---|
[k8s] 쿠버네티스 Service와 Deployment (0) | 2023.12.19 |
[k8s] 쿠버네티스 기초 (0) | 2023.12.19 |
댓글