EKS 클러스터에 API 어플리케이션 배포하기
.
Data_Engineering_TIL(20210804)
[학습자료]
“클라우드 네이티브를 위한 쿠버네티스 실전 프로젝트” 책을 읽고 실습한 내용입니다.
** 동양북스, 아이자와 고지&사토 가즈히코 지음, 박상욱 옮김
참고자료 URL : https://github.com/dybooksIT/k8s-aws-book
[학습내용]
“Infra as a code(cloudformation)를 이용하여 디비구축하기”에 이어서 진행을 한 실습을 진행한 내용임
** URL : https://minman2115.github.io/DE_TIL252
- 실습의 최종 목표
서비스의 최종 구현 목표
아키텍처 관점에서 최종목표
- 오늘의 실습목표
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에 레포지토리를 등록해준다.
그 다음엔 도커를 설치하고 도커 이미지를 빌드한다.
[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"}
그러면 서비스 리소스와 연결된 로드밸런서가 어떻게 생성되어 있는지 아래와 같이 콘솔화면에 접속해서 확인할 수 있다.