Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Slack과 Rust로 Amazon ECS에서 서비스 배포하기

751 views

Published on

정확한 제목은 "slack과 *Rust*로 amazon ecs에서 서비스 배포하기"입니다.

2018-09-19
AWS한국사용자모임 #container 소모임
https://www.facebook.com/groups/awskrug/

Published in: Technology
  • Login to see the comments

Slack과 Rust로 Amazon ECS에서 서비스 배포하기

  1. 1. Amazon ECS에 서비스 배포하기 2018-09-19 feat. Slack & Rust AWSKRUG 통합소모임 #container
  2. 2. • 유은총 • 2015년부터 Spoqa에서 근무 • 2011년부터 Amazon Web Services 사용 • 4년째 Amazon ECS 사용 • 전업 Python 프로그래머 • 2017년부터 TypeScript 사용 • 2015년부터 React 사용 • 2014년부터 Rust 프로그래밍 시작 • 잡역부 풀스택 프로그래머 2 발표자
  3. 3. 동종업계 1위의 오프라인 매장 포인트 멤버십 및 고객 관리 솔루션 누적 이용자 수 1,700만명, 가맹 매장 수 10,000점 (한국˙일본 합계) 위치 정보 기반의 오프라인 타겟 광고 서비스 핵심 파트너 3 Spoqa
  4. 4. • 2014년까지 도도 포인트는 커다란 모놀리틱 시스템으로 돌아가고 있었음 • 마이크로서비스로 가자 • 각 팀에서 제각각 서비스를 만들기 시작하면 답이 없겠다 • 적어도 배포 시스템은 일원화해야 한다 4 마이크로서비스 아키텍쳐로의 여행
  5. 5. • 괜찮은 패키징 솔루션 • 언어˙라이브러리와 무관하게 사용 가능 • 로컬에서도 이미지 빌드 및 실행이 가능하다 • EC2 + AMI보다 가벼운 배포 절차를 구성할 수 있음 • 클러스터링은 어떻게 하지…… • Docker Swarm이 갓 등장한 시기 • CoreOS? DC/OS?? Kubernetes??? 5 Docker
  6. 6. • Geofront의 전례를 따라…… • https://spoqa.github.io/2014/07/09/geofront.html • 스포카 마이크로서비스를 위한 플랫폼 구축이 목표 • 최종적으로 private subnet 안에 ECS 클러스터를 구성하는 것으로 마무리 • 원대한 목표가 있었지만 사이드잡이 다 그렇듯이 용두사미로 끝남 • 당초 계획했던 통합 배포 시스템이나 서비스 디스커버리 같은 건 온데간데없고…… 6 Project Blackmoon
  7. 7. 7 Longinus
  8. 8. • 결국 다른 팀에 계시던 분께서 만들어냄 • Stateless: 별도의 DB 없이 동작 • Docker Hub + Slack Button API • AWS Lambda 위에서 도는 가벼운 서비스 • Python + Zappa • 일단 설정하고 나면 Slack에서 간단히 배포 가능 8 Longinus
  9. 9. • 셋업이 귀찮음 • 새 서비스를 추가할 때마다 손으로 웹훅 주소를 Docker Hub 콘솔에다 붙여 넣어야 • Stateless의 한계 • 필요한 정보를 모조리 웹훅 URL에 때려넣으니 URL 길이 제한에 걸린다 • 결국 몇몇 서비스는 하드코딩하게 됨 • 로컬 테스트는……? • 개발용 Lambda를 따로 띄워서……?? 9 그렇게 한동안 버텼지만……
  10. 10. • 갑자기 일반인 코스프레 • Longinus를 계승 • 최대한 설정 없이 쓸 수 있는 방향으로 • Docker Hub 대신 Amazon ECR을 쓰자 • 로컬 테스트를 하기 쉽게 만들자 • AWS Lambda + Python ➡ Docker + Rust 10 Crane
  11. 11. ?
  12. 12. • 시스템 프로그래밍 언어 • 조합 가능한 멀티코어 프로그래밍 • 패턴 매칭 + 제네릭 • 강한 타입 + 타입 추론 • Cargo 패키지 시스템 • 멀티플랫폼 • 메모리 안전 • 쓰레기 수집기(GC) 없음 • 매크로 12 Rust?
  13. 13. • 예전 프로젝트에서 그럴싸하게 써먹어 본 적이 있음 • https://www.rust-lang.org/ko-KR/friends.html • 통상적으로는 C++ 또는 Java와 쓰이는 분야가 겹치는 언어 • 이걸로 웹 서비스도 만들 수 있을까? • C++ 같았으면 가성비가 안 나오는 일이지만 Rust라면……? 13 Why Rust?
  14. 14. 여기서부터는 거의 Rust 얘기만 나옵니다 ( ͡° ͜ʖ ͡°)
  15. 15. • Slack API 및 웹훅 • 웹훅 요청을 받을 웹 서비스가 필요 • 일반 웹훅 API로는 안 됩니다 Slack App을 만들어야 함 • ECR에 이미지가 올라오는 시점을 알아내기 • CloudTrail ➡ CloudWatch Events ➡ SQS • 주기적으로 ReceiveMessage에 롱 폴링 • 보통 15초 정도 이내에 반응함 • 새 이미지로 ECS 서비스 배포 • 새 이미지와 같은 이름을 쓰는 작업 정의를 죄다 찾고 업데이트 • 업데이트된 작업 정의를 쓰는 서비스를 죄다 찾아 배포 • ECR을 사용한다면 별도의 설정이 필요없음 15 시작
  16. 16. • 모르겠고 일단 쓰레드 따서 돌린다! • SQS로부터 메시지를 받을 쓰레드를 웹 서비스가 도는 쓰레드와 별도로 실행 • 내친김에 워커 쓰레드도 하나 만들자 • 쓰레드 사이의 통신은 MPSC 채널을 사용 • 하다 보니까 대책없이 쓰레드를 쓰고 있는데 이거 괜찮을까? 16 Fearless Concurrency!
  17. 17. • 트레이트(trait): 일종의 인터페이스 • 동시성 프로그래밍의 안전을 지키는 두 트레이트 • Send: 쓰레드 경계를 넘을 수 있음 (예: 참조를 포함하지 않는 대부분의 타입) • Sync: 여러 쓰레드가 참조해도 괜찮음 (예: Mutex<T>, RwLock<T>, AtomicI32 등) • 위의 규칙을 만족하지 않는 코드는 컴파일 에러 • 언어적으로 참조 공유와 값 변경이 극도로 제약되어 있음 • 뮤텍스가 보호하는 값은 반드시 보호될 거라는 확신이 생김 • 전례없이 편안한 마음으로 멀티쓰레드 프로그래밍을 할 수 있습니다 • 동적 타입 언어 쓰다가 정적 타입 언어로 돌아올 때의 그 느낌처럼 17 괜찮아, 문제없다
  18. 18. • 직업 프로그래머로 일하기 시작할 적에 새겨두었던 교훈 • 멀티쓰레드를 써야 할 것 같다면, 일단 다시 생각하라 • 그래도 써야 할 것 같다면, 멀티프로세싱이나 여하간 다른 방법을 찾아라 • Python GIL이 제 프로그래머로서의 가치관에 큰 영향을 끼쳤습니다 😂 • 결과적으로 제대로 된 멀티쓰레딩 경험이 전무한 상태였음 • 왠지는 모르겠지만 봇이 자꾸 먹통이 된다 • 메모리 누수 같은 리소스 누수나 논리적인 동시성 오류까지 Rust 컴파일러가 잡아주지는 못하더라 • 쓰레드를 잘 죽이려면 어떻게 해야 하지? 18 그러나
  19. 19. • 컴파일러와의 끝없는 투쟁 • 경험자들의 증언: 잘못될 가능성이 있는 코드는 다른 언어보다 Rust로 쓰기가 더 어렵더라 • 생각보다 그런 코드가 많습니다 • 가끔 논리적으로는 맞지만 타입 검사를 통과 못하는 경우를 밟기도 함 • 다행히 지속적으로 개선되고 있습니다 # • 함수형 프로그래밍만큼은 아니더라도 어느 정도 코딩 습관을 바꾸게 됩니다 19 안전의 대가
  20. 20. • 기본적으로 거대한 JSON 값 20 ECR 이벤트 파싱
  21. 21. • Serialization/deserialization • https://serde.rs/ • Killer feature • 직렬화˙역직렬화 방법과 직렬화된 데이타 포맷이 서로 직교적 • serde_json, serde_yaml, serde_cbor, serde_protobuf, …… • Rust 데이타 직렬화의 사실상 표준 21 Serde
  22. 22. • Rust용 AWS SDK (like boto) • https://www.rusoto.org/ • 대부분의 AWS 서비스를 지원함 • SQS, ECS, ECR 모두 사용 가능했음 • SO HUGE! • 모든 API 요청˙응답˙에러에 대한 구조체와 열거형이 각각 따로 만들어져 있음 • 컴파일 시간 증가에 혁혁한 공로 22 Rusoto
  23. 23. • CloudWatch Events로 ECS 클러스터 상태 이벤트를 수신할 수 있음 # • 컨테이너 인스턴스나 서비스 상태를 모니터링한다거나 하는 데 쓸 수 있겠다 • 또는 배포 기록을 보존하거나 23 데이타베이스도 좀 써 봅시다
  24. 24. • Rust용 ORM 중에 가장 멀쩡한 라이브러리 • http://diesel.rs/ • 마이그레이션, 쿼리 DSL, 타입과 스키마 간 매핑 등등 기본적인 기능은 갖추고 있음 • PostgreSQL, MySQL, SQLite 지원 • 유의점 • Rust는 객체 지향 언어가 아닙니다 • 그래서 엄밀히 말해 이건 ORM은 아닙니다 • Java나 Python 같은 OO 언어에서와는 조금 다른 설계가 필요합니다 24 Diesel
  25. 25. 25 Diesel
  26. 26. • Rocket • Flask처럼 생김 • Rust여서 가능할 법한 기능들: request guards • Flask처럼 보이기 위해 일부 nightly compiler 기능에 의존 • 비동기 지원 없음 • Rouille • Rust스러운 웹 프레임워크 디자인을 찾기 위한 시도 • 하나의 커다란 request ➡ response 루프와 같은 구조 • 사실상 표준인 Hyper, Tokio 등과 아무 상관 없는 스택 • 역시나 비동기 지원 없음 26 웹 프레임워크
  27. 27. • https://actix.rs/ • 적당한 절충안 • 그럭저럭 익숙한 생김새 • 모든 것이 비동기! • Actix 액터 프레임워크 기반 • 내친 김에 쓰레드 쓰던 코드들을 전부 액터 기반으로 갈아버림 27 Actix-web
  28. 28. • 그래도 멀티쓰레드보단 많은 경험이 있었음 • Gevent/Eventlet, asyncio, Promise 등등... • Futures • Promise랑 비슷합니다 • 프로덕션용으로는 0.1이 널리 쓰임. 0.3을 준비 중인 상태 • Tokio • Futures 기반의 비동기 I/O 프레임워크 • Work-stealing task executor가 딸린 기본 런타임 제공 28 비동기 프로그래밍
  29. 29. • 소유권 및 lifetime 검사와 안 좋은 방식으로 상호작용 • 사실상 참조를 쓸 수 없는 수준 • async fn + Futures 0.3이 미래다 • 그래서 제가 미래에 살고 있는데요 nightly compiler의 세계는 험난하네요 • sync ➡ tokio-core ➡ tokio로 가는 과도기를 직격으로 겪음 • Rusoto가 꽤 늦게 트렌드를 따라 온 편이라 섞어 쓰느라 고생했었습니다 • Actix vs Tokio • Actix 자체 런타임은 전체 애플리케이션 수준에서 단일 쓰레드를 강제 (tokio-core의 잔재) • 일부 액터에 한해 쓰레드 풀링으로 동작 30 헬게이트 오픈
  30. 30. 31 우여곡절 끝에 그래도 여기까지 왔습니다
  31. 31. • 예상했던 대로 rapid prototyping은 좀 어려움 • 메모리는 정말 조금 먹습니다 64MiB 이하 • Crane 자체도 ECS 서비스라 자기 자신을 배포하는 것도 되고 나름 만족하고 있습니다 • 비동기 프로그래밍을 하고 싶으시면 일단 기다리세요 • 올해 안에 async fn이 포함된 Rust 2018 edition이 나옵니다 • 웹 프레임워크는 일단 Actix-web 쓰세요 😂 32 그래서 할만하던가요
  32. 32. • 서비스 롤백 • 클러스터 유지보수 자동화 • 웹 콘솔 • 신규 서비스 등록 • 회사 내 다른 서비스도 Rust로? • CI와 연동 및 이미지 자체 빌드 (AWS CodeBuild!) • 여러 리전에 걸친 클러스터 관리하기 • 오픈소스? • Slack App으로 공개? 33 앞으로 하고 싶은 것
  33. 33. We’re Hiring! mailto:recruit@spoqa.com
  34. 34. 서울 본사 서울특별시 강남구 테헤란로 420 메이플타워 9층 TEL 02-544-6463 FAX 02-544-6460 부산 지사 부산광역시 부산진구 부전동 426-7 신동아오피스텔 1007호 TEL 02-544-6463 FAX 02-544-6460 주식회사스포카 SEOUL·BUSAN·TOKYO 도쿄 지사 〒151-0053 東京都渋谷区代々木1-21-12ヤマ ノ26ビル 3F TEL 03-6869-3610 Question?
  35. 35. • a = b는 기본적으로 복사가 아닌 이동 • 언제나 하나의 값에 하나의 변수만 존재함. 구조체 필드에 넣거나 함수 인자로 전달해도 마찬가지. • 마지막으로 값을 담았던 변수가 사라지는 지점이 그 값이 메모리에서 해제되는 지점 • 이동 의미론은 바꿀 수 없음. 언제나 C memcpy/memmove와 동등한 동작 • 복사는 a = b.clone()으로 명시적으로 하는 것이 기본 • 복사가 안전한 타입에 한해서 a = b로 복사가 가능 • 참조(&T)는 C 또는 C++의 포인터처럼 동작 • 어떤 참조도 자기가 참조한 변수보다 오래 남아있을 수 없음 • mut를 붙이지 않은 모든 변수와 참조는 불변(immutable) • 동시에 하나의 &mut만 존재할 수 있음 (iterator invalidation 같은 걸 방지) • 위에서 설명한 규칙은 모두 컴파일 시간에 검사됨 36 부록: Rust 주요 기능 요약
  36. 36. • enum은 tagged union • match 식으로 패턴 매칭을 해서 원하는 값을 꺼낸다 • 널 포인터가 없고 명시적으로 None을 나타낼 수 있는 Option<T>가 존재 • 에러 처리에 쓰이는 Result<T, E>도 enum 타입 • 트레이트(trait)는 일종의 인터페이스. 제네릭 타입을 한정짓거나 동적 디스패치를 하는 데에 쓰임. • 다른 라이브러리의 타입이나 i32 같은 기본 타입에 내가 정의한 트레이트를 구현하는 게 가능함 • Haskell의 타입 클래스 같은 겁니다 • Send나 Sync 같은 일부 트레이트는 자동으로 구현됨 • 클래스 같은 건 없어요 37 부록: Rust 주요 기능 요약 (2)

×