오늘 배운 것

오늘 오후까지 이어지던 SZ-85 작업은 계속 길어질 것 같아서 드래그앤 드롭 구현에 이상이 없는 정도에서 잠시 머지하고, 나는 그 동안 미뤄왔던 또 다른 급한 이슈를 처리하려고 했다. 

 

바로 github action, ECR, ECS를 통해 깃허브의 메인 브랜치의 코드를 도커 이미지로 빌드해서 ECR에 업로드하고, ECS를 통해 ECR에 업로드된 도커 이미지를 실행하는 일을 했다. 

 

사실 ECR로 이미지를 업로드하는 일까지는 순탄했고, 그 이후에 ECS의 클러스터를 설정하고, fargate와 EC2 중에서 나름 고민해서 선택을 했다. fargate는 서버리스로, 좀 더 간단한 설정을 할 수 있다는 장점이 있는 반면 EC2는 설정을 커스텀해야 하는 부분이 있지만 비용 측면에서 좋다고 했다. 그러다 문득 팀원이 멘토님께서 EC2 인스턴스를 그냥 쓰지 말고 EC2 스팟 요청을 통해 더 저렴하게 사용하라고 했던 것 같다고 말해줘서, 아 그러면 어차피 EC2 스팟 인스턴스를 써야 하는 거니 EC2를 써야 하겠다는 생각이 들어 EC2 인스턴스를 선택했다. 

 

그래서 EC2를 선택했는데 클러스터에 할당된 EC2 인스턴스가 없다는 말을 듣고 EC2 스팟 요청을 해야하나 말아야하나 하다가 클러스터 설정에서 '서비스 추가' 대신에 '태스크 추가'를 발견해서 그걸 눌러보았더니 참고하던 블로그와 똑같은 UI가 떴다. 

 

그래서 태스크 추가에서도 여러 설정을 하는데, '네트워크 모드'라는 옵션이 있었다. 옆의 설명을 읽어보니 태스크에서 ECS가 실행시키는 컨테이너가 어떤 네트워크 설정을 가질지를 결정하는 것 같았다. 기본값은 awsvpr로 되어있었는데 이건 fargate에서 필요한 설정이라고 되어 있어서 내가 선택한 EC2에 해당하는 옵션은 아닌 것 같았다. 그래서 docker network ls 명령어를 치면 기본값으로 항상 보이던 bridge 네트워크가 떠올라서 bridge를 선택했다. 예상해보건대 bridge 옵션을 선택하고, 만약 여러 컨테이너를 같이 사용해야 한다면 그때 그 컨테이너들을 같은 네트워크상에 위치시키면 되는 게 아닌가 싶다. (만약 그게 아니라면 설정을 바꾸면 되니, 큰 문제는 아니다.) 

 

그리고 이렇게 환경 변수를 따로 설정하는 부분도 있었는데, 나는 이미 AWS secrets manager에서 환경 변수를 설정해주었어서 이걸 사용한다면 언제 사용해야 하는지도 궁금했다. 

 

그런데 ECS에서 EC2 옵션을 선택하니 사용 가능한 인스턴스가 없다고 떴다. 그래서 GPT의 도움을 받아 원인을 찾아보니 EC2 인스턴스에 접속해서 별도로 ECS에 연결하는 설정을 해 주어야 하는 것으로 보였다. 그래서 그 작업을 한 다음, EC2 옵션에서 다시 ECS에 연결한 인스턴스가 뜨는 것을 확인한 다음에 다음 작업으로 넘어갈 수 있을 것 같았다. 

 

EC2 (스팟) 인스턴스를 생성할 때, User Data 섹션에 이 텍스트를 붙여넣어야 하는 것 같다. 환경변수 설정을 해 주는 것이라고 생각했다. 

echo ECS_CLUSTER=onestep-production4 >> /etc/ecs/ecs.config

 

그렇게 스팟 인스턴스를 실행시키고 퍼블릭 DNS 주소를 확인해서 EC2 서버에 접속하려고 하니, 퍼블릭 DNS 주소가 없었고 프라이빗 DNS 주소만 있었다. 원래 이런건지는 모르겠다. 그래서 탄력적 IP(elastic IP) 주소를 하나 생성하고, 이를 생성한 스팟 인스턴스에 할당했다. 다시 확인해 보니 스팟 인스턴스에 퍼블릭 DNS 주소가 잘 나왔다. 

 

그리고 종종 까먹지만 처음에 ssh로 접속을 시도할 때 실패하는데, 보안 그룹에서 TCP 통신을 허용하고 22번 포트를 열어주면 무사히 접속이 된다. 그 이유는 ssh로 통신할 때 TCP 프로토콜을 쓰고 22번 포트를 통하기 때문이다. 


그런데 ECS에서 태스크를 정의하고, 서비스나 태스크를 만들 때마다 항상 클러스터에서 실행 가능한 EC2 인스턴스가 없다는 문구가 계속 떴다. 심지어 관련 유튜브 영상을 참고했는데도, 해당 영상에서는 ECS 클러스터를 만들면서 자동으로 EC2 인스턴스를 생성했는데, 내가 했을 때는 그렇게 되지가 않아서 뭔가 놓친 것이 있다는 생각이 들었다. 

 

그래서 GPT에게 도움을 요청하니, IAM 권한을 생성하라고 말해주어서 AmazonEC2ContainerServiceforEC2Role라는 권한을 생성했다. 정확히 무슨 역할인지는 모르지만, EC2 컨테이너를 다른 AWS 서비스에서도 생성할 수 있도록 하는 역할일 것으로 추측했다. 찾아보니 AWS 내부의 여러 서비스들을 같이 사용할 때, 가령 서비스A에서 서비스B에 접근해야 하는 경우, IAM에서 그 작업을 실행할 수 있도록 역할을 생성해줘야 하는 것 같았다. 

 

 궁금한 점

1. 탄력적 IP 주소의 용도는 무엇일까

2. 왜 처음에 스팟 인스턴스를 생성하면 퍼블릭 DNS 주소는 기본적으로 할당되지 않고 별도로 할당해 주어야 하는 것일까 -> 찾아보니 추가 설정에서는 '퍼블릭 주소 할당'이 있다! 불필요하게 퍼블릭 주소(리소스)를 할당하지 않고, 사용자가 원할 때 할당하도록 한 것 같다. 

3. sudo yum과 sudo apt-get 이라는 명령어를 많이 보는데 이 명령어들의 구체적인 뜻은 무엇일까

4. Amazon EBS는 무엇인가

5. IAM 서비스는 무엇을 위해서, 왜 필요한가 b/c 종종 IAM 계정이나 권한을 생성하라는 말을 많이 들어서 궁금하다. 

 

 

'개발 일기장 > SWM Onestep' 카테고리의 다른 글

20240728 TIL  (2) 2024.07.28
20240727 TIL: ECR ECS 적용기  (0) 2024.07.27
20240725 TIL  (0) 2024.07.25
20240724 TIL  (0) 2024.07.24
20240723 TIL  (2) 2024.07.23

 오늘 배운 것

오늘은 삽질해서 막히던 SZ-85번의 하위 이슈 중 하나를 팀원들의 도움으로 같이 해결했다. 세부 문제 상황은, 투두 리스트들 아래 텍스트 인풋을 받는 Input 컴포넌트를 누르면 텍스트 인풋 창이 활성화되지 않고 키보드가 활성화되었다가 바로 비활성화되는 문제였다. 

팀원들과 웹엑스로 회의를 하면서 문제가 되는 컴포넌트(DailyTodos 안의 컴포넌트)를 KeyboardAvoidingView로 한번 더 감싸 보았더니 된다고 했다. 

 

사실 어떤 원리로 문제가 해결되었는지는 모르겠다. 왜냐하면 이미 바깥 화면에서 KeyboardAvoidingView를 사용하고 있었고, 그래서 굳이 한번 더 감쌀 생각을 안 한 것이었기도 하기 때문이다. 또한 GPT한테 물어봤을 때는 컴포넌트(아마도 Input 컴포넌트)가 계속 텍스트창이 활성화될 때마다 다시 렌더링 되어서 텍스트 창 클릭 -> 활성화 -> 다시 렌더링됨 -> 초기 값인 비활성화...의 루프를 타는 것이라고 생각하였는데 결국 그도 아니었던 것이다. 

 

이 부분은 KeyboardAvoidingView에 대해서도 더 알아봐야 알 수 있을 것 같고, 그래도 모호하다면 멘토님께 이 상황을 한번 공유드려봐도 어떤 실마리가 보일 것 같다. 이제 다음 하위 이슈들을 처리할 수 있을 것 같아 마음이 조금이나마 홀가분해졌다. 

 

 

아직 SZ-85번 이슈의 완료를 위해선 몇 개의 하위 이슈들이 남아있지만, 이걸 완료해야 다른 팀원이 '드래그앤드롭 기능과 현재 컴포넌트를 연결하는 이슈' 및 'AI가 하위투두를 자동으로 생성해주는 이슈'를 처리할 수 있어서, 이걸 얼른 완료하는 게 중요하다. 그래야 나도 다음 급한 이슈인 'ECR, ECS를 통해 자동 배포하기'를 해볼 수 있을 것 같다. 암튼 파이팅이다.

 

'개발 일기장 > SWM Onestep' 카테고리의 다른 글

20240727 TIL: ECR ECS 적용기  (0) 2024.07.27
20240726 TIL  (0) 2024.07.26
20240724 TIL  (0) 2024.07.24
20240723 TIL  (2) 2024.07.23
20240721 TIL  (1) 2024.07.22

 오늘 배운 것

오늘도 SZ-85번 이슈에서 삽질을 했다. 대부분은 상태관리에 관한 문제였다. 특히 프로젝트에서는 상태관리를 위해 zustand와 useContext API를 사용하는데, zustand 라이브러리를 통해서는 useTodoStore()와 useModalStore()라는 2가지의 store를 사용한 것이 복잡성의 원인이 되었다. 

 

정확히는 selectedTodo라는 모달창에서 선택된 투두를 저장하기 위한 상태 변수가 useModalStore()에 선언되어 있었는데, 이것을 useTodoStore()에 선언된 줄 알고 useTodoStore에서 불러와서 제대로 모달창이 나타나지 않는 문제가 있었다. 

 

또한 Jwt Parse error도 있었다. GPT에게 물어보니 토큰이 발급된 시간(iat)가 컴퓨터의 로컬 시간보다 빨라서 발생하는 에러로, 컴퓨터의 로컬 시간을 점검해 볼 것을 말해줬다. 나는 맥을 쓰고 있어서, 맥의 환경설정에 들어가서 서버가 애플의 시간 서버(time.apple.com)에서 제대로 시간을 받아오고 있는지를 확인했다. 그런데 이미 애플의 서버에서 제대로 현지 시각을 잘 받아오고 있어서, 오류의 원인은 알았지만 해결은 할 수 없었다... 현재 오류는 확률적으로 발생하는데, 만약 매번 또는 빈번하게 발생한다면 그때 더 자세히 알아봐야 할 것 같다. 

 

'개발 일기장 > SWM Onestep' 카테고리의 다른 글

20240727 TIL: ECR ECS 적용기  (0) 2024.07.27
20240726 TIL  (0) 2024.07.26
20240725 TIL  (0) 2024.07.25
20240723 TIL  (2) 2024.07.23
20240721 TIL  (1) 2024.07.22

 오늘 배운 것

투두 안에 하위 투두가 있고, 각 투두의 설정 아이콘을 눌러 모달창을 열 수 있고, 그 모달창을 통해 투두를 수정 및 삭제할 수 있는 기능을 개발 중이다. 원래 어제부터 만들었었는데, 시간을 많이 썼음에도 문제가 하나 터지고 겨우 해결하면 또 다음 게 생기고 이런 식이라서 아직도 막히고 있다. 

 

오늘 배운 것은 상태 관리의 중요성이다. 투두 컴포넌트들은 크게 CategoryTodos > DailyTodos > DailyTodo > DailySubTodo의 계층 구조(사실 이 정도면 그냥 재귀 구조로 호출해도 될 것 같다...)로 되어 있는데, 문제는 TodoModal이라는 모달창 컴포넌트의 위치였다. 원래는 이 TodoModal이 DailyTodo와 DailySubTodo 컴포넌트에 있었는데, 그러다 보니 카테고리 값을 바꾸고 나서 투두를 클릭할 때 상태 관리가 제대로 되지 않아서 이전 카테고리의 투두 값을 모달에 띄운다는 문제가 있었다. 

 

요즘은 개발을 할 때 GPT와 티키타카를 많이 하는데, 내가 문제 상황을 인식해서 그걸 풀어서 설명하면 GPT가 해결책을 제시해주고, 그럼 내가 그걸 따라해보거나 찾아보면서 이해하는 식으로 작업하고 있다. 모든 투두 컴포넌트 파일들을 첨부하고 GPT에게 위의 문제를 해결할 방법을 제시해달라고 하니, GPT는 기존의 CategoryTodos > DailyTodos > DailyTodo > TodoModal의 구조 대신 TodoModal을 CategoryTodo의 바로 아래, DailyTodos와 같이 배치했다. 그리고 그 대신 useContext나 zustand를 사용해서 상태 관리를 하는 식으로 코드를 제시해줬다. 

 

그래서 이 방법을 사용해서 기존에 있었던 zustand로 투두 상태를 관리하는 useTodoStore() 대신, useModalStore()를 사용했다. 사실 상태 관리나 컴포넌트 작성에 정답은 없어서 useContext()를 사용할지 zustand를 사용할지 고민이었는데, 단순 변수와 set 함수(useState를 통해 쌍으로 생성되는 변수와 함수)만 있는 게 아니라면 zustand도 괜찮을 것 같다고 판단해서 zustand를 사용했다. 

 

아직 모달창은 시작도 못 했고, CategoryTodos 컴포넌트 안에서도 해결해야 할 과제가 많이 남아있어 막막하지만, 근데 또 시간을 많이 썼는데 안 된 거라서 조금만 더 해보고 안 되면 일단 자고 내일 일찍 일어나서 조금이라도 더 해 봐야 할 것 같다. 늘 항상 막힘없이 개발이 잘 되는 게 아니고 막힐 때가 더 많은데, 오늘은 그런 날이었던 것 같다. 그래도 그런 날의 기록이라도 남기길 잘한 것 같다:)

 

 

'개발 일기장 > SWM Onestep' 카테고리의 다른 글

20240727 TIL: ECR ECS 적용기  (0) 2024.07.27
20240726 TIL  (0) 2024.07.26
20240725 TIL  (0) 2024.07.25
20240724 TIL  (0) 2024.07.24
20240721 TIL  (1) 2024.07.22

오늘 배운 것

github actions, workflow를 이용해서 CI/CD를 구축할 때는 무작정 AWS EC2 서버에 접속해서 도커를 띄우는 것이 아니다. 

대신 AWS의 ECS(Elastic Container Service), ECR(Elastic Container Registry) 서비스를 사용한다. 즉 순서는 다음과 같다. 

1. github actions에서 도커 이미지를 만든 다음에 ECR에 올린다. 

2. ECR의 signal을 사용해서 ECS에게 ECR에 도커 이미지가 업로드되었다고 알림을 보내거나, github actions에서 직접 ECS에게 알림을 보낸다. 

3. 배포 완료

 

그리고 도메인을 처음으로 돈 주고 사 보았고, 그것을 Route53이라는 AWS의 서비스를 통해서 AWS와 연결시켜 보았다. 구체적인 스텝이 정확히는 기억이 안 나서 겨우겨우 약간이나마 복기해 보았다. 

1. 여러 사이트를 통해서 도메인 사기

2. Route53을 이용해서 도메인 연결하기

3. 서브넷 설정하기. 그래야 하나의 서버가 실행되다가 죽어도 다른 서브넷의 서버로 연결할 수 있다고 하셨던 것 같다. 

4. 로드 밸런서 설정하기. 각 지역(aws region)에 따라서 request가 들어오면 그에 맞는 region의 subnet으로 보내주는 역할이라고 이해했다. 

 

또한 우리가 있는 ap-northeast-2 aws region은 서브넷이 크게 4개(2a, 2b, 2c, 2d)이기 때문에, 총 서브넷은 기본으로 생성되어 있는 private 서브넷 4개와, 우리가 직접 생성한 public 서브넷 4개로 총 8개면 된다고 하셨다. 

 

그리고 CloudWatch로 로그도 저장해야 한다고 하셨다. 백엔드의 경우는 CloudWatch, 프론트의 경우는 잘 모르지만 알아보아야겠다. 

 

또한 배포용 DB라면 RDS를 사용하는 것이 제일 깔끔하다고 말씀해 주셨다. 

또한 LexoRank 라이브러리도, 원래는 프론트 단에서만 정렬을 하려고 했는데 그럴 수가 없다고 하셨다. 왜냐하면 프론트 단에서 정렬 관련 정보를 보내면 백엔드에서 이를 아예 validation하지 않고 저장하는 것은 거의 사실상 불가능하기 때문이다. 

 

더 궁금한 것

도커 대신 ECR, ECS를 사용하는 것이 권장되는 이유가 궁금하다. 

github workflow도 내부 소스코드를 보면 github actions를 통해 구현된 것이라고 한다. 이 원리가 궁금하다. 

 

'개발 일기장 > SWM Onestep' 카테고리의 다른 글

20240727 TIL: ECR ECS 적용기  (0) 2024.07.27
20240726 TIL  (0) 2024.07.26
20240725 TIL  (0) 2024.07.25
20240724 TIL  (0) 2024.07.24
20240723 TIL  (2) 2024.07.23

+ Recent posts