[인턴일지] GraphQL과 Apollo Federation을 활용한 마이크로서비스 아키텍처 설계 및 구현하기

osohyun0224·2024년 2월 4일
1

슬기로운 인턴생활

목록 보기
8/15
post-thumbnail

안녕하세요, 대학생 웹 개발 인턴 Garden입니다.

프리온보딩의 2번째 날은 사내 백엔드 엔지니어 Rachel께서 사내의 서버 구현, 즉 백엔드 개발 내용을 수업해주셨습니다.

2. Rachel의 Backend

한 줄 배운내용

  1. GraphQL의 기본적인 작동 원리와 주요 구성요소
  2. 마이크로서비스 아키텍처(MSA)와 Federation을 통한 서비스 결합 방법
  3. Apollo Federation을 사용하여 서비스 간 엔티티 참조

개념에 대한 공부한 자세한 내용은 아래의 벨로그 글로 정리하였습니다.

실습 과제

  • 실습 1
    • 목표: template_subgql 파악하기, local test 환경 익숙해지기
    • config 내 mode return 스키마 구현
    • local gateway에 subgql 부착해보기 (npm run gateway.docker, npm run gateway 이용)
    • local gateway에서 자신의 스키마에 요청보내고 답 얻기
    • config.mode의 값을 return 하는 스키마를 만들기

  • 실습 2
    • 목표: federation entity 이해하기, template_subgql을 통해 federation 경험해보기
    • 다른 subgql의 entity 참조해보기
      • subscriberCount10times - 특정채널의 구독자수의 10배 구해주는 필드 구현
        • @external, @requires
      • Channel의 schema (참고)
type Channel @key(fields: "channelId") {
  "유튜브 채널ID"
  channelId: ID!
	//(중략)
 "구독자수"
  subscriberCount: Float
}
  • 해당 스키마에 type Cannel subscriberCount10times 필드를 추가하고, 해당 필드와 관련된 resolver(10배 해주는 함수)를 구현해주면 됨
  • 잘 적용되었는지 확인해보려면 local에 gateway 띄워서 부착한 뒤 확인

프론트엔드 개발만을 공부해온 사람이라 자바스크립트 쓴다 말고는 해오던거에서 공통적인게 없는 부분을 오늘도 이게 가능한가라는 생각이 들었으나,,, 불가능해보이는 것을 가능하게 하는 Rachel의 친절한 강의력에 반해서 오늘도 모든 과제를 마칠 수 있었습니다 ㅋㅋㅋㅋㅋ

과제 진행 기록은 다음과 같습니다.

[1] grapql 스키마를 정의

  • 가능한 쿼리와 뮤테이션, 그리고 처리할 데이터 타입을 정의하는 GraphQL API의 도면이다!
type Query {
  getMyName : String
}

@ 여기서 뮤테이션이란, 데이터를 변경(crud)하기 위한 요청, 쿼리와 달리 여러 효과를 가지는 것을 의미한다.

[2] resolver 정의

  • 우리가 정의한 쿼리 또는 뮤테이션의 각 필드에 대한 실제 데이터를 반환하는 함수가 정의되어있고 우리는 데이터 소스와 상호 작용하면서 클라이언트에서 요청한 데이터를 해결하는 영역이다.
...

import Config from "@src/Config";
import GqlFunction from "@src/component/GqlFunction";

import Garden from "./index.js";

class Resolver {
  static async Resolvers_getMyName(){
    return await new Garden().getGardenName(Config.get()); 
  }
};

export const resolvers = {
  Query: {
    getMyName: Resolver.Resolvers_getMyName,
  }
};

[3] index.js 정의

...
import GqlFunction from "@src/component/GqlFunction";
import EntityLoader from "@src/component/EntityLoader";

const DefaultPostCacheTimeoutSeconds = 3600 * 24;
const PostCacheTimeoutSeconds = process.env.PostCacheTimeoutSeconds || DefaultPostCacheTimeoutSeconds;

export default class Garden {
  constructor(config){
    this.config = config;
  }
  getGardenName(config) {
    return config.mode;
  }
}

[4] config 파일 정의

....
{
  "app": "[부서].api.garden",
  "port": "5110",
  "registry.name": "[이름]",
  "registry.tag": "$mode.garden",
  "registry.path": //비공개[각 프로젝트에 알맞게 수정]
  "git.branch.prod": "prod.garden",
  "deploy.namespace": "sandbox"
}
...

[5] secret 파일정의

회사 코드라 올릴 수가 없지만 secret 파일을 올바르게 정의해야합니다. 해당 파일의 config 파일과 함께 올바르게 구현되도록 수정합니다.


과제를 실습한 내용의 코드는 아래의 깃허브 레포에서 확인할 수 있습니다.
Rachel's Graphql + Apollo Assign

번외, 에러 대응

이 과제를 저희 회사 사내 쿠버네티스에 배포까지 하면서 잘 부착되었는지 확인했습니다. 하지만 이것도 공부하기 위한 용으로 계속 쿠버네티스에 서버가 배포 있다면 리소스를 낭비하는 일이기 때문에 다시 unregister로 스키마까지 깔끔하게 지워야하는데요, 근데 이 과정에서 제가 지난 데브옵스 강의에서 과제를 하면서 발생한 에러 대응에 사용한 buildx때문에 unregister가 되지 않았습니다... 해당 내용을 정리한 글은 아래에 정리했습니다.

인턴일지-데브옵스-도커와 쿠버네티스

단순히 쿠버네티스에서 해당 서버 pod이든 deployment이든 지우면 안되는이유가 스키마가 그대로 남아있기 때문에 절대 그냥 지우면 안되고 unregister로 스키마까지 깔끔하게 삭제해야합니다.

클라이언트에서 서버 요청을 보내고 있는데 없는 상태로 되니까 ?? 상태에 빠지게 되는 것입니다.

이를 지우는 방법은 해당 서버파일이 존재하는 상태에 deployment에 가서 unregister 명령어를 통해 직접 삭제해주면 됩니다.

이 에러 대응은 기존 파일 삭제하고 mybuilder를 다지운다음 권한 받고 재 배포를 진행했습니다 ㅎㅎ

profile
Garden / Junior Frontend Developer

0개의 댓글