EKS 클러스터에 API 어플리케이션 배포하기

2021-08-04

.

Data_Engineering_TIL(20210804)

[학습자료]

“클라우드 네이티브를 위한 쿠버네티스 실전 프로젝트” 책을 읽고 실습한 내용입니다.

** 동양북스, 아이자와 고지&사토 가즈히코 지음, 박상욱 옮김

참고자료 URL : https://github.com/dybooksIT/k8s-aws-book

[학습내용]

“Infra as a code(cloudformation)를 이용하여 디비구축하기”에 이어서 진행을 한 실습을 진행한 내용임

** URL : https://minman2115.github.io/DE_TIL252

  • 실습의 최종 목표

서비스의 최종 구현 목표

architecture3

아키텍처 관점에서 최종목표

architecture2

  • 오늘의 실습목표

API 어플리케이션을 빌드하고, 도커 컨테이너 이미지로 만들어서 ECR에 등록한 다음에 이 이미지를 이용해서 EKS 클러스터에 API 어플리케이션을 배포해보자.

Cloudformation으로 간단하게 EKS cluster 구동하기(https://minman2115.github.io/DE_TIL251) 에서 생성한 ‘ ec2에서 glone한 파일들에서 아래와 같이 소스코드를 빌드한 다음 생성된 jar를 이용해 도커 컨테이너 이미지를 만들것이다.

  • 실습내용

먼저 eks 클러스터를 구동했던 클라이언트 ec2에 접속해서 아래와 같이 java 11 버전을 아래와 같이 설치한다.

[ec2-user@ip-10-0-1-12 backend-app]$ sudo yum install tree -y

[ec2-user@ip-10-0-1-12 backend-app]$ java --version
-bash: java: command not found

[ec2-user@ip-10-0-1-12 backend-app]$ sudo yum install java-11-amazon-corretto -y

[ec2-user@ip-10-0-1-233 ~]$ sudo /usr/sbin/alternatives --config java

There is 1 program that provides 'java'.

  Selection    Command
-----------------------------------------------
*+ 1           /usr/lib/jvm/java-11-amazon-corretto.x86_64/bin/java

Enter to keep the current selection[+], or type selection number: 1


[ec2-user@ip-10-0-1-12 backend-app]$ java --version
openjdk 11.0.12 2021-07-20 LTS
OpenJDK Runtime Environment Corretto-11.0.12.7.1 (build 11.0.12+7-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.12.7.1 (build 11.0.12+7-LTS, mixed mode)

[ec2-user@ip-10-0-1-12 backend-app]$ javac -version
javac 11.0.12

[ec2-user@ip-10-0-1-12 backend-app]$ which javac
/usr/bin/javac

[ec2-user@ip-10-0-1-12 backend-app]$ readlink -f /usr/bin/javac
/usr/lib/jvm/java-11-amazon-corretto.x86_64/bin/javac

[ec2-user@ip-10-0-1-12 backend-app]$ sudo vim /etc/profile

# 최하단에 아래와 같이 문구추가
export JAVA_HOME=/usr/lib/jvm/java-11-amazon-corretto.x86_64

# SSH 재접속한다 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 반드시 !!!!!!!!!!!!!!!!!!!!!!!!!!!

[ec2-user@ip-10-0-1-12 ~]$ echo $JAVA_HOME
/usr/lib/jvm/java-11-amazon-corretto.x86_64

[ec2-user@ip-10-0-1-12 ~]$ $JAVA_HOME/bin/javac -version
javac 11.0.12

그리고 gradle로 git clone 받은 파일을 빌드한다.

[ec2-user@ip-10-0-1-12 ~]$ sudo yum install git -y

[ec2-user@ip-10-0-1-12 ~]$ git clone https://github.com/dybooksIT/k8s-aws-book.git

[ec2-user@ip-10-0-1-12 ~]$ tree k8s-aws-book/
k8s-aws-book/
├── autoscaling
│   ├── cluster-autoscaler.yaml
│   ├── components.yaml
│   └── horizontal-pod-autoscaler.yaml
├── backend-app
│   ├── build.gradle
│   ├── Dockerfile
│   ├── gradle
│   │   └── wrapper
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── scripts
│   │   ├── 10_ddl.sql
│   │   ├── 11_drop_ddl.sql
│   │   ├── 20_insert_sample_data.sql
│   │   └── 21_truncate.sql
│   ├── settings.gradle
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── k8sbook
│       │   │       └── sampleapp
│       │   │           ├── BackendApplication.java
│       │   │           ├── common
│       │   │           │   └── handler
│       │   │           │       └── SampleAppExceptionHandler.java
│       │   │           └── presentation
│       │   │               ├── api
│       │   │               │   ├── HealthApi.java
│       │   │               │   ├── LocationApi.java
│       │   │               │   └── RegionApi.java
│       │   │               └── dto
│       │   │                   ├── HealthDto.java
│       │   │                   ├── LocationDto.java
│       │   │                   ├── LocationsDto.java
│       │   │                   ├── RegionDto.java
│       │   │                   └── RegionsDto.java
│       │   └── resources
│       │       ├── application.properties
│       │       ├── hibernate.properties
│       │       └── logback.xml
│       └── test
│           ├── java
│           │   └── k8sbook
│           │       └── sampleapp
│           │           └── presentation
│           │               └── api
│           │                   ├── HealthApiTest.java
│           │                   ├── LocationApiTest.java
│           │                   ├── RegionApiMockTest.java
│           │                   └── RegionApiTest.java
│           └── resources
│               └── k8sbook
│                   └── sampleapp
│                       └── presentation
│                           └── api
│                               └── RegionApiMockTest_testGetAllRegions.json
├── batch-app
│   ├── build.gradle
│   ├── Dockerfile
│   ├── gradle
│   │   └── wrapper
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── sample_data
│   │   ├── error
│   │   │   └── sample_location3.csv
│   │   └── normal
│   │       ├── sample_location1.csv
│   │       └── sample_location2.csv
│   ├── settings.gradle
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── k8sbook
│       │   │       └── sampleapp
│       │   │           ├── aws
│       │   │           │   ├── AWSConfiguration.java
│       │   │           │   └── S3FileHandler.java
│       │   │           ├── BatchApplication.java
│       │   │           ├── LocationDataLoader.java
│       │   │           └── LocationFileProcessor.java
│       │   └── resources
│       │       ├── application.properties
│       │       ├── hibernate.properties
│       │       └── logback.xml
│       └── test
│           ├── java
│           │   └── k8sbook
│           │       └── sampleapp
│           │           ├── aws
│           │           │   ├── S3FileHandlerTest.java
│           │           │   ├── S3TestUtil.java
│           │           │   ├── S3TestUtilTest.java
│           │           │   └── TestAWSConfiguration.java
│           │           ├── BatchApplicationTest2.java
│           │           └── BatchApplicationTest.java
│           └── resources
│               └── k8sbook
│                   └── sampleapp
│                       ├── a.csv
│                       ├── aws
│                       │   └── a.csv
│                       ├── b.csv
│                       ├── location1.csv
│                       ├── location2.csv
│                       └── rev2_a.csv
├── cicd
│   ├── cloudformation
│   │   ├── buildspec-apply.yaml
│   │   ├── buildspec-build.yaml
│   │   └── cicd-environment-template.yaml
│   └── kustomization
│       ├── base
│       │   ├── deployment.yaml
│       │   ├── kustomization.yaml
│       │   └── service.yaml
│       ├── prod
│       │   └── kustomization.yaml
│       └── test
│           ├── deployment.yaml
│           └── kustomization.yaml
├── column-deployment-update
│   ├── 01_nginx_deployment_k8s.yaml
│   └── 02_nginx_deployment_cpu200_k8s.yaml
├── column-loadbalancer-https
│   └── 23_service_backend-app_https_k8s.yaml.template
├── db-docker-compose
│   ├── createdb.sh
│   ├── createuser.sh
│   └── docker-compose.yaml
├── eks-env
│   ├── 01_base_resources_cfn.yaml
│   ├── 02_nginx_k8s.yaml
│   ├── 10_rds_ope_cfn_mysql.yaml
│   ├── 10_rds_ope_cfn.yaml
│   ├── 20_create_namespace_k8s.yaml
│   ├── 21_db_config_k8s.yaml.template
│   ├── 22_deployment_backend-app_k8s.yaml.template
│   ├── 23_service_backend-app_k8s.yaml
│   ├── 30_s3_cloudfront_cfn.yaml
│   ├── 40_s3_batch_cfn.yaml
│   ├── 41_config_map_batch_k8s.yaml.template
│   ├── 42_batch_secrets_k8s.yaml.template
│   ├── 43_cronjob_k8s.yaml.template
│   └── cloudwatch-yaml
│       ├── cloudwatch-namespace.yaml
│       ├── cwagent-configmap.yaml
│       ├── cwagent-daemonset.yaml
│       ├── cwagent-serviceaccount.yaml
│       └── fluentd.yaml
├── frontend-app
│   ├── assets
│   │   └── style
│   │       ├── app.styl
│   │       └── variables.styl
│   ├── jest.config.js
│   ├── layouts
│   │   ├── default.vue
│   │   └── error.vue
│   ├── middleware
│   ├── nuxt.config.js
│   ├── package.json
│   ├── package-lock.json
│   ├── pages
│   │   ├── index.vue
│   │   └── regionDetail.vue
│   ├── plugins
│   │   └── axios.js
│   ├── static
│   │   ├── favicon.ico
│   │   └── v.png
│   ├── store
│   │   └── index.js
│   └── test
├── LICENSE
├── readme
│   ├── cover.jpg
│   └── errata
│       └── errata.md
├── README.md
├── sample-app-common
│   ├── build.gradle
│   ├── gradle.properties
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── k8sbook
│       │   │       └── sampleapp
│       │   │           ├── domain
│       │   │           │   ├── model
│       │   │           │   │   ├── Location.java
│       │   │           │   │   └── Region.java
│       │   │           │   └── service
│       │   │           │       ├── LocationService.java
│       │   │           │       └── RegionService.java
│       │   │           └── persistence
│       │   │               ├── entity
│       │   │               │   ├── AbstractEntity.java
│       │   │               │   ├── BatchProcessingEntity.java
│       │   │               │   ├── BatchProcessingFileEntity.java
│       │   │               │   ├── LocationEntity.java
│       │   │               │   └── RegionEntity.java
│       │   │               └── repository
│       │   │                   ├── BatchProcessingFileRepository.java
│       │   │                   ├── BatchProcessingRepository.java
│       │   │                   ├── LocationRepository.java
│       │   │                   └── RegionRepository.java
│       │   └── resources
│       │       └── application.properties
│       └── test
│           ├── java
│           │   └── k8sbook
│           │       └── sampleapp
│           │           ├── domain
│           │           │   └── service
│           │           │       └── LocationServiceTest.java
│           │           ├── persistence
│           │           │   └── repository
│           │           │       ├── LocationRepositoryTest.java
│           │           │       └── RegionRepositoryTest.java
│           │           └── TestApplication.java
│           └── resources
│               ├── application.properties
│               ├── hibernate.properties
│               └── logback.xml
└── security
    ├── calico.yml
    ├── network-policy-all-deny.yaml
    ├── network-policy-allow-http-from-serviceB2ServiceA.yaml
    ├── network-policy-sample-serviceA.yaml
    └── rbac.yaml

95 directories, 143 files

[ec2-user@ip-10-0-1-12 ~]$ cd /home/ec2-user/k8s-aws-book/backend-app

[ec2-user@ip-10-0-1-12 backend-app]$ ll
total 28
-rw-rw-r-- 1 ec2-user ec2-user 1290 Aug  4 07:39 build.gradle
-rw-rw-r-- 1 ec2-user ec2-user  395 Aug  4 07:39 Dockerfile
drwxrwxr-x 3 ec2-user ec2-user   21 Aug  4 07:39 gradle
-rw-rw-r-- 1 ec2-user ec2-user  101 Aug  4 07:39 gradle.properties
-rwxr-xr-x 1 ec2-user ec2-user 5305 Aug  4 07:39 gradlew
-rw-rw-r-- 1 ec2-user ec2-user 2185 Aug  4 07:39 gradlew.bat
drwxrwxr-x 2 ec2-user ec2-user  103 Aug  4 07:39 scripts
-rw-rw-r-- 1 ec2-user ec2-user   65 Aug  4 07:39 settings.gradle
drwxrwxr-x 4 ec2-user ec2-user   30 Aug  4 07:39 src

[ec2-user@ip-10-0-1-12 backend-app]$ sudo chmod 755 ./gradlew

[ec2-user@ip-10-0-1-12 backend-app]$ ./gradlew clean build
Downloading https://services.gradle.org/distributions/gradle-5.2.1-bin.zip
...................................................................................

Welcome to Gradle 5.2.1!

Here are the highlights of this release:
 - Define sets of dependencies that work together with Java Platform plugin
 - New C++ plugins with dependency management built-in
 - New C++ project types for gradle init
 - Service injection into plugins and project extensions

For more details see https://docs.gradle.org/5.2.1/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :test
2021-08-04 08:36:01.521 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
2021-08-04 08:36:01.523 [SpringContextShutdownHook] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
2021-08-04 08:36:01.530 [SpringContextShutdownHook] INFO  o.s.s.c.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
2021-08-04 08:36:01.534 [SpringContextShutdownHook] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'

BUILD SUCCESSFUL in 2m 59s
14 actionable tasks: 12 executed, 2 up-to-date

[ec2-user@ip-10-0-1-12 libs]$ cd /home/ec2-user/k8s-aws-book/backend-app/build/libs

# 아래와 같이 jar 파일이 빌드 된것을 확인할 수 있다.
[ec2-user@ip-10-0-1-12 libs]$ ll
total 37076
-rwxrw-r-- 1 ec2-user ec2-user 37961838 Aug  4 08:35 backend-app-1.0.0.jar

그런다음에 아래와 같이 ECR에 레포지토리를 등록해준다.

1

그 다음엔 도커를 설치하고 도커 이미지를 빌드한다.

[ec2-user@ip-10-0-1-12 libs]$ sudo amazon-linux-extras install docker -y
    
[ec2-user@ip-10-0-1-12 libs]$ sudo service docker start
Redirecting to /bin/systemctl start docker.service

[ec2-user@ip-10-0-1-12 libs]$ sudo docker info
Client:
 Context:    default
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 20.10.4
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Cgroup Version: 1
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc io.containerd.runc.v2 io.containerd.runtime.v1.linux
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc version: %runc_commit
 init version: de40ad0
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 4.14.238-182.422.amzn2.x86_64
 Operating System: Amazon Linux 2
 OSType: linux
 Architecture: x86_64
 CPUs: 2
 Total Memory: 1.909GiB
 Name: ip-10-0-1-12.ap-northeast-2.compute.internal
 ID: 43ID:NNPG:JWYE:QV6L:JZIS:3XHB:GTAC:WAWQ:OKNY:RMT4:IBFD:JQ7B
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

[ec2-user@ip-10-0-1-12 backend-app]$ cd /home/ec2-user/k8s-aws-book/backend-app
        
[ec2-user@ip-10-0-1-12 backend-app]$ cat Dockerfile
FROM amazoncorretto:11
LABEL maintainer="k8sbook"

RUN yum install -y glibc-langpack-ko
ENV LANG ko_KR.UTF8
ENV LC_ALL ko_KR.UTF8
RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", \
 "-verbose:gc", \
 "-Xlog:gc*:stdout:time,uptime,level,tags", \
 "-Djava.security.egd=file:/dev/./urandom", \
 "-jar", \
 "/app.jar"]

[ec2-user@ip-10-0-1-12 backend-app]$ sudo docker build -t k8sbook/backend-app:1.0.0 --build-arg JAR_FILE=build/libs/backend-app-1.0.0.jar .
Sending build context to Docker daemon  54.17MB
Step 1/10 : FROM amazoncorretto:11
11: Pulling from library/amazoncorretto
d36ac8072fa2: Pull complete
f170fe744cfd: Pull complete
Digest: sha256:75558b1ec7aa332e62f57f708fb82aa1a648a4e4840ada287a00b8c656e066a0
Status: Downloaded newer image for amazoncorretto:11
 ---> 2b27f3c83c92
Step 2/10 : LABEL maintainer="k8sbook"
 ---> Running in 596d32304f94
Removing intermediate container 596d32304f94
 ---> 67cec10dff6f
Step 3/10 : RUN yum install -y glibc-langpack-ko
 ---> Running in 8a2489f921a2
Loaded plugins: ovl, priorities
Resolving Dependencies
--> Running transaction check
---> Package glibc-langpack-ko.x86_64 0:2.26-48.amzn2 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package                Arch        Version               Repository       Size
================================================================================
Installing:
 glibc-langpack-ko      x86_64      2.26-48.amzn2         amzn2-core      326 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 326 k
Installed size: 2.5 M
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : glibc-langpack-ko-2.26-48.amzn2.x86_64                       1/1
  Verifying  : glibc-langpack-ko-2.26-48.amzn2.x86_64                       1/1

Installed:
  glibc-langpack-ko.x86_64 0:2.26-48.amzn2

Complete!
Removing intermediate container 8a2489f921a2
 ---> 768b1e75a7db
Step 4/10 : ENV LANG ko_KR.UTF8
 ---> Running in 046224daf706
Removing intermediate container 046224daf706
 ---> aec73d23c658
Step 5/10 : ENV LC_ALL ko_KR.UTF8
 ---> Running in 248dd50d23e6
Removing intermediate container 248dd50d23e6
 ---> d7b7c03d8e59
Step 6/10 : RUN ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime
 ---> Running in a7b0f7aff231
Removing intermediate container a7b0f7aff231
 ---> 7d9f3b82eb70
Step 7/10 : VOLUME /tmp
 ---> Running in 048f35d2deee
Removing intermediate container 048f35d2deee
 ---> 1a4562cd09e4
Step 8/10 : ARG JAR_FILE
 ---> Running in 6f7065b0ed23
Removing intermediate container 6f7065b0ed23
 ---> 904dc6c16fb1
Step 9/10 : COPY ${JAR_FILE} app.jar
 ---> 4d890b6d0d9b
Step 10/10 : ENTRYPOINT ["java",  "-verbose:gc",  "-Xlog:gc*:stdout:time,uptime,level,tags",  "-Djava.security.egd=file:/dev/./urandom",  "-jar",  "/app.jar"]
 ---> Running in 6180607844dd
Removing intermediate container 6180607844dd
 ---> 198d5e7bc728
Successfully built 198d5e7bc728
Successfully tagged k8sbook/backend-app:1.0.0
    
[ec2-user@ip-10-0-1-12 backend-app]$ sudo docker images
REPOSITORY            TAG       IMAGE ID       CREATED          SIZE
k8sbook/backend-app   1.0.0     198d5e7bc728   37 seconds ago   745MB
amazoncorretto        11        2b27f3c83c92   33 hours ago     445MB

[ec2-user@ip-10-0-1-12 backend-app]$ aws ecr get-login-password --region ap-northeast-2 | sudo docker login --username AWS --password-stdin xxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

[ec2-user@ip-10-0-1-12 backend-app]$ sudo docker tag k8sbook/backend-app:1.0.0 xxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/k8sbook/backend-app:1.0.0

[ec2-user@ip-10-0-1-12 backend-app]$ sudo docker push xxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/k8sbook/backend-app:1.0.0
The push refers to repository [xxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/k8sbook/backend-app]
ad0c79f12e76: Pushed
d56ef1a76963: Pushed
52c019af6ef2: Pushed
02b224ecb2e6: Pushed
6404f374ee85: Pushed
1.0.0: digest: sha256:748734ae71873837c1674732014a6559374457a74a218ed307cee9d92b63410c size: 1374

EKS 클러스터에 API 어플리케이션 배포하기

EKS 클러스터에 API 어플리케이션을 배포하기 위해서는 EC2에서 아래와 같은 단계를 진행해주면 된다.

STEP 1) 네임스페이스 생성

STEP 2) 컨텍스트 생성

STEP 3) 디비 접속용 시크릿 등록

STEP 4) API 어플리케이션 외부 공개

[ec2-user@ip-10-0-1-104 eks-env]$ cd /home/ec2-user/k8s-aws-book/eks-env

[ec2-user@ip-10-0-1-104 eks-env]$ ll
total 60
-rw-rw-r-- 1 ec2-user ec2-user 3135 Aug  6 14:53 01_base_resources_cfn.yaml
-rw-rw-r-- 1 ec2-user ec2-user  180 Aug  6 14:53 02_nginx_k8s.yaml
-rw-rw-r-- 1 ec2-user ec2-user 7924 Aug  6 14:53 10_rds_ope_cfn_mysql.yaml
-rw-rw-r-- 1 ec2-user ec2-user 7957 Aug  6 14:53 10_rds_ope_cfn.yaml
-rw-rw-r-- 1 ec2-user ec2-user   58 Aug  6 14:53 20_create_namespace_k8s.yaml
-rw-rw-r-- 1 ec2-user ec2-user  153 Aug  6 14:53 21_db_config_k8s.yaml.template
-rw-rw-r-- 1 ec2-user ec2-user 1397 Aug  6 14:53 22_deployment_backend-app_k8s.yaml.template
-rw-rw-r-- 1 ec2-user ec2-user  190 Aug  6 14:53 23_service_backend-app_k8s.yaml
-rw-rw-r-- 1 ec2-user ec2-user 1253 Aug  6 14:53 30_s3_cloudfront_cfn.yaml
-rw-rw-r-- 1 ec2-user ec2-user 1677 Aug  6 14:53 40_s3_batch_cfn.yaml
-rw-rw-r-- 1 ec2-user ec2-user  195 Aug  6 14:53 41_config_map_batch_k8s.yaml.template
-rw-rw-r-- 1 ec2-user ec2-user  158 Aug  6 14:53 42_batch_secrets_k8s.yaml.template
-rw-rw-r-- 1 ec2-user ec2-user 1939 Aug  6 14:53 43_cronjob_k8s.yaml.template
drwxrwxr-x 2 ec2-user ec2-user  154 Aug  6 14:53 cloudwatch-yaml

# STEP 1) 네임스페이스 생성
# eks-work라는 네임스페이스를 생성하고, 이 네임스페이스에 API 어플리케이션을 배포할 것이다.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl apply -f 20_create_namespace_k8s.yaml
namespace/eks-work created

[ec2-user@ip-10-0-1-104 eks-env]$ cat 20_create_namespace_k8s.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: eks-work

# 네임스페이스 설정값 확인
# Kubeconfig 파일에는 컨텍스트마다 네임스페이스를 지정할 수 있다.
# 아래와 같이 네임스페이스 설정값을 최초에 확인을 해보면 NAMESPACE가 이름이 따로 없는 디폴트 형태의 네임스페이스로 잡혀있는 것을 알 수 있다.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl config get-contexts
CURRENT   NAME                                                   CLUSTER                                     AUTHINFO                                               NAMESPACE
*         minsu.park@eks-work-cluster.ap-northeast-2.eksctl.io   eks-work-cluster.ap-northeast-2.eksctl.io   minsu.park@eks-work-cluster.ap-northeast-2.eksctl.io

# STEP 2) 컨텍스트 생성
# eks-work라는 새로운 네임스페이스를 사용할 것이기 때문에 아래와 같이 eks-work라고 설정된 새로운 컨텍스트를 생성하고 활성화 한다.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl config set-context eks-work --cluster eks-work-cluster.ap-northeast-2.eksctl.io --user minsu.park@eks-work-cluster.ap-northeast-2.eksctl.io --namespace eks-work
Context "eks-work" created.

# 위에 명령어를 실행하면 네임스페이스로 eks-work가 지정된 컨텍스트가 생성되었고, 이제 활성화된 컨텍스트로 변경해준다.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl config use-context eks-work
Switched to context "eks-work".

[ec2-user@ip-10-0-1-104 eks-env]$ kubectl config get-contexts
CURRENT   NAME                                                   CLUSTER                                     AUTHINFO                                               NAMESPACE
*         eks-work                                               eks-work-cluster.ap-northeast-2.eksctl.io   minsu.park@eks-work-cluster.ap-northeast-2.eksctl.io   eks-work
          minsu.park@eks-work-cluster.ap-northeast-2.eksctl.io   eks-work-cluster.ap-northeast-2.eksctl.io   minsu.park@eks-work-cluster.ap-northeast-2.eksctl.io
		  
# STEP 3) 디비 접속용 시크릿 등록
# API 어플리케이션이 디비에 접속하기 위한 비밀번호 등을 저장하는 '시크릿' 이라는 것을 아래와 같이 생성한다.
# rds 엔드포인트는 클라우드 포메이션의 출력값을 확인하면 되고, 디비 패스워드는 시크릿 매니저 서비스에서 확인하면 된다.
[ec2-user@ip-10-0-1-104 eks-env]$ DB_URL=jdbc:postgresql://eks-work-db.xxxxxxxx.ap-northeast-2.rds.amazonaws.com/myworkdb DB_PASSWORD='wdivF6S}_gC#Ifog' envsubst < 21_db_config_k8s.yaml.template | kubectl apply -f -
secret/db-config created

# API 어플리케이션 배포
# 디플로이먼트 오브젝트를 생성한다. 디플로이먼트를 생성하면 그 뒤에 레플리카 셋이 생성되며 레플리카셋 뒤에는 파드가 생성된다.
[ec2-user@ip-10-0-1-104 eks-env]$ ECR_HOST=xxxxxxxxxx.dkr.ecr.ap-northeast-2.amazonaws.com envsubst < 22_deployment_backend-app_k8s.yaml.template | kubectl apply -f -
deployment.apps/backend-app created

[ec2-user@ip-10-0-1-104 eks-env]$ cat 22_deployment_backend-app_k8s.yaml.template
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-app
  labels:
    app: backend-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: backend-app
  template:
    metadata:
      labels:
        app: backend-app
    spec:
      containers:
      - name: backend-app
        image: ${ECR_HOST}/k8sbook/backend-app:1.0.0
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        env:
        - name: DB_URL
          valueFrom:
            secretKeyRef:
              key: db-url
              name: db-config
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              key: db-username
              name: db-config
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              key: db-password
              name: db-config
        readinessProbe:
          httpGet:
            port: 8080
            path: /health
          initialDelaySeconds: 15
          periodSeconds: 30
        livenessProbe:
          httpGet:
            port: 8080
            path: /health
          initialDelaySeconds: 30
          periodSeconds: 30
        resources:
          requests:
            cpu: 100m
            memory: 512Mi
          limits:
            cpu: 250m
            memory: 768Mi
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 2"]

# kubectl get all 명령어를 이용해서 확인해보면 디플로이먼트 외에 레플리카셋과 파드가 생성된것을 알 수 있다.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl get all
NAME                              READY   STATUS    RESTARTS   AGE
pod/backend-app-7fb899969-h2vd9   0/1     Running   0          64s
pod/backend-app-7fb899969-hbcjn   0/1     Running   0          64s

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/backend-app   0/2     2            0           65s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/backend-app-7fb899969   2         2         0       65s

# STEP 4) API 어플리케이션 외부 공개
# 어플리케이션을 쿠버네티스 클러스터에 배포는 했지만 아직 외부 클러스터에서는 API 호출이 불가능하다.
# 쿠버네티스에는 배포된 파드를 외부에 공개하기 위해 '서비스'라는 리소스를 제공한다.
# 서비스는 공개범위에 따라 몇가지 타입이 정의되어 있는데 여기서는 로드밸런서라는 서비스 타입을 사용할 것이다.
# 배포한 파드 앞에 로드밸런서를 위치시키고, 인터넷에서 요청을 받으면 파드에서 동작중인 어플리케이션을 호출할 수 있다.
# API 어플리케이션에 서비스 리소스를 생성하기 위해 아래와 같은 매니패스트 파일을 apply 해보자.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl apply -f 23_service_backend-app_k8s.yaml
service/backend-app-service created

[ec2-user@ip-10-0-1-104 eks-env]$ cat 23_service_backend-app_k8s.yaml
apiVersion: v1
kind: Service
metadata:
  name: backend-app-service
spec:
  type: LoadBalancer
  selector:
    app: backend-app
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080

# 로드밸런서 서비스가 추가된것을 알수 있다.
[ec2-user@ip-10-0-1-104 eks-env]$ kubectl get all
NAME                              READY   STATUS    RESTARTS   AGE
pod/backend-app-7fb899969-h2vd9   1/1     Running   0          104s
pod/backend-app-7fb899969-hbcjn   1/1     Running   0          104s

NAME                          TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)          AGE
service/backend-app-service   LoadBalancer   10.100.228.215   xxxxxxxxx.ap-northeast-2.elb.amazonaws.com   8080:31747/TCP   3s

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/backend-app   2/2     2            2           105s

NAME                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/backend-app-7fb899969   2         2         2       105s

# curl로 elb의 주소와 통신해보면 아래와 같이 api 서비스가 잘 제공되고 있음을 확인할 수 있다.
[ec2-user@ip-10-0-1-104 eks-env]$ curl -s http://xxxxxxxxx.ap-northeast-2.elb.amazonaws.com:8080/health
{"status":"OK"}

그러면 서비스 리소스와 연결된 로드밸런서가 어떻게 생성되어 있는지 아래와 같이 콘솔화면에 접속해서 확인할 수 있다.

11