Integration Test Using TestContainers

이미지
Spring Boot 와 RDBMS 환경에서 개발하면서 Test 를 작성할 때, 테스트 환경의 경우 주로 H2 를 사용한다. H2 는 몇 줄만 추가해주면 Test 환경에서 사용이 가능하기 때문에 설정이 매우 쉽다. 하지만 production 환경에서는 MySQL, PostgreSQL, MS SQL, Oracle 등 H2 와는 다른 Database 를 사용하고 있다면 이슈가 발생할 수 있다. 기본적으로 지원되는 문법이 다르거나 Database Engine 이 동작하는 방식이 달라서 Test 를 신뢰할 수 없다. 이것은 본질적으로 Test Code 를 작성하는 의미를 지키기 힘들어진다. H2 에서 compatible 모드를 지원하지만 본질적으로 완전하게 동일한 환경을 보장할 수 없다.  아래 링크를 통해서 확인할 수 있다. http://www.h2database.com/html/features.html#compatibility 모든 database engine 들은 조금씩 다르게 동작합니다. H2 는 ANSI 표준을 지원하고 다른 database 와 호환되도록 노력합니다. 하지만 여전히 차이가 존재합니다. https://www.h2database.com/html/advanced.html#acid 또한, Transaction 도 다르게 동작한다. ACID 의 개념을 빠뜨릴 수 없는데  MySQL 의 경우 default Isolation Level 은 REPEATABLE READ 이지만 H2 default Isolation Level 은 READ COMMITED 이다. Phantom Read 이슈가 발생하게 된다.  물론 설정을 REPEATABLE READ 로 변경하고 Production 환경과 최대한 비슷하게 설정하고나서 H2 사용을 고려해 볼 수 있다. 하지만, 쉽게 설정할 수 있다는 H2 의 장점이 없어진다. 따라서 Production 환경과 최대한 동일한 환경으로 쉽고 빠르게 설정하여 테스트를 진행할 수 있도록 TestContaine...

Github Action - Trigger Another Repository Workflow and Push Self

이미지
 GitOps 를 구현하는 과정에서 고민했었던 부분 그리고 해결한 방법을 정리하려고 한다. GitOps 에서 크게 Application Repository ( Code Repository ) 와 Environment Repository ( State Repository ) 두 가지의 Repository 로 정의가 된다. 조직의 프로세스나 크기, 형태, 철학마다 다르겠지만, 일반적인 회사에서나 어떤 프로젝트에서 협업을 할 때 보통 개발팀과 운영팀이라는 개념으로 나뉠 수 있을 것이다. 이 때 보통 Application Repository 는 개발팀이 Environment Repository 는 운영팀이 관리할 것이다. 개발팀에서 지속적으로 새로운 기능 및 유지 보수를 진행함에 따라서 소프트웨어의 변경이 일어난다. 해당 변경은 CI 를 통해서 새로운 Container Image 를 생산할 것이다. 이 때 운영팀은 Image 들의 버전을 Environment Repository 에 반영해야 한다.  이 과정에서 여러가지 의문점이 들었다. 운영팀은 Environment Repository 의 Application 들의 버전 변경을 수동으로 반영할까 자동으로 반영할까? 수동으로 반영하는 프로세스라면 휴먼에러가 발생하지 않을까? 발생한다면 어떻게 대처할까? 자동으로 반영한다면 그것또한 무결함을 보장할 수 있을까? 이러한 의문점들은 귀결은 "Environment Repository 를 어떻게 관리하는게 좋을까?" 이다. 조금만 생각해보면 해당 질문에 정답이 있는것은 아니라는 결론이다. 모든것은 현재 해당 프로젝트 해당 조직이 처한 context 에 따라 다를것이다. 규모가 큰 조직일수록 관리해야할 application 이 많아서 수동으로 관리하는 것에 한계를 느낄 것이고, 반대로 규모가 작은 조직일수록 수가 적은 application 들을 관리하기 위해서 자동화를 하는 것에 더 비용을 크게 느낄수 도 있을 것이다.  개인적으로 자동화는 단기적인 관점...

About GitOps

이미지
 GitOps 란 무엇인가? cloud native application 의 CD(Continuous Deployment) 의 구현 방법이다. infrastructure 을 운영할 때 Git 을 포함한 CD tools 을 포함하여 이미 개발자들에게 친숙한 tools 을 사용하는 방법을 통해서 개발자 중심적인 경험에 초점을 두고 만들어졌다.  GitOps 의 가장 중심적인 개념은 아래의 3가지이다. 1. automated process (자동화된 프로세스) 2. 현재 infrastructure 상태의 declarative descriptions (선언적인 상세) 3. Git repository  Git repository 는 production 환경에서 현재 infrastructure 의 상태를 기술하는 declarative description 가지며 자동화된 프로세스를 통해서 실제 infrastructure 가 관리된다. 새로운 application 또는 기존의 application 을 update 할 경우, Git repository 을 update 함으로써 infrastructure 를 변경한다. 또한 이는 자동화된 프로세스로 모든것이 이루어진다. 그렇다면 왜 GitOps 를 사용해야 하는가? 더 빠른 그리고 더 자주 배포할 수 있다. 모든 CD technology 는 배포성에 대해서 장점으로 말한다. 하지만 GitOps 가 특별한 점은 배포를 위해서 CD tools 변경이 필요없다는 점이다. 모든것이 VCS (version control system) 을 통해서 이루어진다. 쉽고 빠른 Error Recovery GitOps 는 모든 infrastructure 의 변경 내역이 Git repository 에 관리된다. 또한 error recovery 를 위해서 git revert 를 진행하고 복구되는 것을 지켜보기만 하면 된다. 쉬운 Credential 관리 오직 Git repository 와 image registry 만 필요하다...

AWS Systems Manager - Session Manager (W terraform)

이미지
흔히 VPC, Subnets 을 설계할 때 Public Subnet 과 Private Subnet 의 형태로 구성이 된다. Public Subnet 의 경우 Load Balancer 혹은 web internet facing 자원들을 배치하게 되고, Private Subnet 의 경우 RDS 나 back-end application 을 배치하게 된다. Private Subnet 의 경우 Public Subnet 과는 다르게 Internet 을 통해서 직접 연결을 할 수 없기 때문에 추가의 작업이 필요하다. 예를 들어, Private Subnet 에 있는 Database 작업을 위해서 접속해야한다. 1. Bastion Host - Public Subnet 에 Bastion Host 를 구성하여 Bastion Host 를 통해서 Private Subnet 의 자원에 접속하고 관리한다. Bastion Host 의 경우 별도로 관리해야할 EC2 혹은 VM 이 증가하게 되는 단점이 있다. 2. VPN - VPN 은 비교적 Bastion Host 나 Security Group 설정에 비해서 비용이 많이 든다. 각각의 장단점이 있기 때문에 상황에 맞게 사용해야 한다. 위의 방법 말고 AWS Session Manager 를 이용할 수 있다.  AWS Session Manager 는 AWS Systems Manager 라는 서비스의 속한 기능으로 EC2 혹은 온프레미스 환경의 VM 들을 관리할 수 있는 기능이다.  Session Manager 가 동작하는 원리는 SSM Agent 를 통해서 Session Manager 와 통신한다. 따라서 접속하려는 EC2 혹은 온프레미스 환경의 VM 에 SSM Agent 가 설치되어야 한다. 또한 EC2 에 적절한 instance profile 이 설정 되어 있어야한다.  - AmazonSSMManagedInstanceCore - AmazonSSMDirectoryServiceAccess 그리고 EC2 의 user da...

Github Action Build and Push Docker Image To ECR By Environment On Multi Modules Gradle Spring Boot Project

이미지
Github Action 을 이용하여 Spring Boot Multi Modules Project 를 환경에 따라 Gradle 을 이용하여 Jar Artifact 를 생성하고 이를 바탕으로 Docker Image Build 와 ECR 에 Push 하는 과정을 정리해보겠다. 1. Project Structure - folder, gradle, dockerfile 먼저 프로젝트 구조는 아래의 이미지와 같다. gradle multi module 의 구조이며 batch, buyer-auth, seller-auth, product, order 로 총 5개의 모듈로 구성되어 있다. 각각의 모듈하위에는 Dockerfile 을 작성했다. 아래는 각 모듈 하위에 있는 Dockerfile 의 예시 이다.  Spring Boot 2.5.4 와 java 11 LTS 를 사용했다. 2. aws ecr private repository, iam user with policy 다음으로 각각의 모듈들의 이미지 저장소로 Private ECR 을 terraform 을 이용하여 아래와 같이 작성했다. 각각의 이미지 태그는 변경이 불가능하도록 IMMUTABLE 을 활성화 했다. Private Repository 로 생성했기 때문에, 해당 레포지에 대하여 읽기/쓰기 작업을 하기 위해서는 별도의 IAM 계정의 권한이 필요하다. 아래의 공식 문서를 통해서 private ecr repository 들에 대해서 이미지를 push 와 pull 을 가능하도록 IAM user 를 설정해야 한다. 혹은 어드민 권한을 가진 IAM user 를 통해서 사용가능 하겠지만, 보안을 준수하는 방법이 아니기 때문에 권한을 세세하게 나누어서 관리하는 것이 권장사항이다. https://docs.aws.amazon.com/ko_kr/AmazonECR/latest/userguide/security_iam_id-based-policy-examples.html 3. github action yaml file 4. enviro...

About Cache & TTL (Time To Live)

이미지
먼저 TTL (Time To Live) 의 개념을 정리해보자. 한국말로 "살아 있을 시간" 으로 해석할 수 있다. 무엇이 살아 있을 시간일까? 주로 TTL 은 Cache 개념과 묶여서 설명할 수 있다. 따라서 Cache 이야기를 먼저해보자. Client Server topology 에서 예를 들자면, Client 가 특정 자원을 Server 에 요청을 할 것이다. Server 는 해당 Client 의 요청에 대해서 응답하기 위해서 Server Side Resource (CPU, Memory etc.) 를 사용할 것이다. 하지만 Client 의 요청이 많아질수록 이는 Server 의 부담이 된다. 만약에 동일한 응답을 Client에게 반환할 경우에 이전의 응답한 결과를 다시 사용할 수 있다면 자원 활용도를 높일 수 있다. 하지만 이전의 응답한 결과에 변경이 발생한다면 Server 는 올바르지 않은 응답을 하게 된다.  이와 같은 현상을 해결하기 위해서는 변경되지 않을 자원만 Cache 를 적용 하거나, 변경되는 자원을 Cache 와 Sync 를 할 수 있는 전략들이 필요하다. Cache 전략은 여러가지가 있고 제공하고자 하는 데이터에 따라 그리고 아키텍쳐에 따라 여러가지 적용 기법이 있겠지만 몇 가지만 들어보겠다. 처한 상황에 따라서 어느 한 가지만 사용할 수도 있고, 여러 전략들을 동시에 취합해서 사용해야 하기도 한다. Lazy Loading / Cache-Aside 이름에서 추측할 수 있듯이, 필요할 때 데이터를 Cache 에 로드하는 전략이다.  Cache Hit 예를 들어, Client 가 Server 에 요청을 한다. 제일 먼저 Cache 저장소에 Cache 데이터가 있는지 확인한다. Cache 저장소에 Cache 데이터가 있고, 해당 Cache 데이터가 stale 이 아닌 최신 상태라면 바로 Client 에 해당 데이터로 응답한다. Cache Miss Cache 데이터가 Cache 저장소에 없거나 stale 이라면, 원래의 데이터 저...

Mutable Infrastructure? Immutable Infrastructure?

이미지
 Mutable Infrastructure 필요할 때 변경하고 업그레이드하는 인프라를 말한다. 예를 들어 10 대의 VM 혹은 여러 대의 물리 서버가 있을 경우, 관리자는 SSH 접속을 통해 하나하나 접속하여 패키지를 수동으로 업그레이드 하거나 다운그레이드 하면서 직접 관리한다. 그리고 기존 서버에 직접 새 코드를 배포한다. 이 과정에서 패키지 설치 혹은 변경에 실패할 수 도 있고 성공할 수 도있다. 이로 인해서 서버간의 조금씩 차이가 발생하게 된다. 제각기 다른 크기의 눈송이와 같다고 하여 snowflake server 라 부른다. 다른 용어로는 configuration drift 라고 한다. Immutable Infrastructure Mutable 과는 다르게, 한 번 프로비전되거나 배포가 되었을 때 해당 서버의 변경을 만들지 않는다. 변경사항이 발생하거나 업데이트가 필요할 때는 해당 서버에서 작업하지 않고, 새로운 VM 혹은 이미지를 통해서 서버를 생성하고 교체한다. 이전 버전의 서버는 버려진다. 재에서 부터 다시 살아나는 피닉스에 비유하여 Phoenix server 라 부른다. Pet (Snowflake Server) and Cattle (Phoenix Server) 눈송이 서버와 피닉스 서버 처럼 비유되는 또 다른 표현이 있다. 바로 pet 과 cattle 이다. 왜 snowflake server 를 pet 에 비유했을까? pet 은 애완동물이다. 애완동물은 하나하나 제각기 주인들에게 특별하게 여겨지며 사랑받는다. 강아지의 경우 이름은 "호두", "룽지", "희동이" 등 각각 특별하다. 이는 snowflake server 처럼 각각의 서버가 다르게 설정될 수 있다는 것에 비유해서 pet 이라는 별칭이 붙게 되었다. 그렇다면 phoenix server 는 어째서 cattle 에 비유될까? cattle 은 소, 가축을 의미한다. 보통 농장에서 가축을 키울 때, 애완동물과는 다르게 사육한다. 가축에게는...