雜夫's Blog development architecture integration operation

코드로 인프라 관리하기 리뷰

한빛출판사의 코드로 인프라 관리하기 라는 책의 리뷰(저자 키프 모리스)

많은 도구, 기술, 플랫폼 들이 나오긴 하지만, 특정한 기술이나 플랫폼에 관한 책은 아님. 왜 서버 인프라를 코드로 관리해야 하고, 생성하고 테스트하는 부분을 자동화 해야 하는지,실제로 인프라 팀의 시각에서 실행할 수 있는 방법을 제시하고 있음.

책 자체에서 저자가 경험한 내용을 바탕으로 설명하고 있는 듯한 느낌이 들고, 내용에 대한 설명도 쉽게 이해할 수 있는 방식으로 진행하고 있음.

소감 및 의견

약간 두서는 없지만, 클라우드 상에서 프로비저닝을 고민할 때 많은 도움이 될 내용들인 것 같아 필요한 부분을 정리해 둠.

서론부분

새로운 업데이트가 나오면, 모든 시스템에 업데이트를 설치해야 했고, 어떤 서버에는 성공적으로 적용했지만, 다른 서버에서는 충돌을 일으켰고, 이를 해결하기 위해 많은 시간을 보내야 했다. 팀의 서버들은 모두 너무 달랐고, 팀은 무인 방식을 신뢰하지 않았다.

코드로 인프라를 관리하기 위한 핵심 개념 - 모든 서버는 처음부터 다시 생성할 수 있으며, 구성도구는 지속적으로 동작한다.

코드로서의 인프라란?

코드로서의 인프라 - SW개발 관례에 기반을 둔 인프라 자동화 방법으로 시스템과 구성을 프로비저닝하고 변경하기 위한 일관되고 반복 가능한 절차에 중점을 둔다.

동적 인프라의 문제점

  • 서버 폭증 - 서버가 늘어날 수록 관리가 힘들어지고, 구성이 달라질 가능성이 생김
  • 구성 편차 - 서버를 일관되게 구성했더라도 시간이 갈 수록 점점 차이가 생길 수 있다. 구성이 다르다고 나쁜 것은 아니나, 변경된 부분이 재생성 될 수 있도록 관리해야 한다. -> 관리되지 않는 변경은 눈송이 서버(snowflake)와 자동화 공포를 일으킨다.
  • 눈송이 서버 - 다른 서버들과 다른, 다시 만들수 없는 서버. 담당자 변경, 매뉴얼 없는 수작업이 반복되면 결국 이렇게 된다.
  • 자동화 공포 - 자동화 공포의 악순환(자동화 도구를 사용하지 않고 구성을 변경 -> 서버 일관성X -> 자동화 도구 실행시 오류에 대한 두려움 ->순환)을 끊어야 한다. 무인 방식으로 운영해야 함.
  • 침식 - 새로운 요구가 없으면 인프라는 시간이 갈 수록 노후된다.(업그레이드,패치,로그파일 등)

코드로서의 인프라의 원칙

  • 시스템은 쉽게 다시 만들 수 있다.
  • 시스템은 일회용이다.
  • 시스템은 일관성이 있다.
  • 절차는 반복 가능하다.
  • 설계는 항상 변한다.

코드로서의 인프라르 위한 도구

동적 인프라 플랫폼

  • 서버, 스토리지 네트워크와 같은 컴퓨팅 자원을 효율적으로 관리할 수 있는 기반을 말함
  • 프로그래밍이 용이해야 함, 온디맨드(자원을 즉시 생성/삭제), 셀프 서비스(인프라 사용자에 의한 변경)
  • 클라우드 이동성 - 클라우드 벤더 업체의 전용 기능을 사용하지 않는다.(차후 이동을 용이하게 함), 컨테이너화가 클라우드 업체 종속을 막는 한 방법이 될수 있다.

인프라 정의 도구

  • Cloudformation(AWS), Terraform(Hashicorp), Heat(OpenStack)
  • Script, 무인 방식의 CLI작업이 가능해야 함
  • 멱등성 - 몇번을 실행하던지 동일한 결과를 나타내야 함.

구성 레지스트리,서버 구성 도구

  • CF엔진, puppet, Chef, Ansible, saltstack 등 + docker도 이 범주에 들어갈 수 있다.
  • 서버 다수에 원격으로 명령을 실행하는 도구 : 많은 서버를 관리하는 데 도움이 될 수 있다.

서버 변경 관리 모형

  • 일시적 변경 관리 - 전통적인 방식
  • 구성 동기화 - 구성관리 도구를 사용하는 방식
  • 불편 인프라 - 서버를 완전히 교체하는 방식으로 구성을 변경하는 인프라, 서버 템플릿 관리를 세밀하게 해야 함
  • 컨테이너화된 서비스 - Docker등의 컨테이너 서비스를 이용하는 방법

컨테이너

  • 도커, 로켓(CoreOS), 워든(Pivoal의 클라우드파운드리), 윈도우 컨테이너 등

컨테이너화의 장점

  • 애플리케이션의 런타임 환경을 호스트 서버와 분리 -> 설치된 어플리케이션이 서로 영향을 미치거나, 충돌하는 문제를 방지할 수 있음.
  • 일관성 있는 런타임 환경을 반복해서 만들 수 있다.
  • 코드로서의 인프라의 모든 일반적인 특성을 포함할 수 있다.

컨테이너는 가상 머신과 다르다.

  • 여러 프로세스를 단일 컨테이너에서 실행하기 보다, 단일 프로세스만 동작하는 여러 컨테이너를 실행하는 방향으로 -> 컨테이너는 마이크로서비스에 적합하다.

서버 프로비저닝 하기

서버를 프로비저닝 하는 방법

  • 서버 프로비저닝 작업 - 하드웨어 할당, 인스턴스 생성, 디스크, OS, SW설치, 서버 및 네트워크를 구성하는 등의 절차를 포함 , 서버 프로비저닝은 미리 해두는 게 더 효율적일 수 있다.(base이미지를 생성하는 등), 또한 프로비저닝은 새 서버를 만드는 것에 한정되지 않는다.
  • 가상화와 자동화 덕분에 각각의 서버에서 서비스를 구축하기가 쉬워졌다. 이는 서비스를 분리해 관리하는 것을 더 쉽게 해준다.

서버의 수명 주기

  • 서버 템플릿 패키징하기 : 서버 다수를 생성하는 데 사용할 수 있도록 공통 요소를 미리 프로비저닝해 둔 서버 이미지.
  • 새 서버를 생성하기 :
  • 서버 업데이트하기 : 생성된 서버의 일관성은 유지되지 않는다. 자동 구성 도구들(Chef, Puppet, Ansible 등)은 이런 문제를 처리할 수 있다.
  • 서버 교체하기 : 경우에 따라 서버를 교체하는 방법이 업데이트 보다 쉬울 수 있다. 불변 인프라는 어떠한 구성 변경이든 서버를 재생성하는 방식을 사용하는 변경 관리 전략이다.
  • 서버 삭제하기

서버에 들어 있는 것들

  • 소프트웨어 : 애플리케이션, 라이브러리, 기타 코드 등
  • 구성 : 시스템과 어플리케이션이 동작하는 방식을 제어하는 데 사용하는 파일
  • 데이터 : 시스템이나 어플리케이션이 생성하고 업데이트 한 파일.

서버의 역할

  • 서버의 사용 목적에 따라 역할을 부여, 때로 상속 관계를 사용할 수 있음. “기본 템플릿 - 웹서버, DB서버 템플릿” 과 같이

서버를 생성하는 패턴

  • 안티패턴:수제 서버 - 가장 쉬운, 손으로 만드는 방법, 수동으로 만든 서버는 만들때마다 생성 옵션을 누군가 선택해야 하고, 매번 다른 구성으로 만들 우려. 즉시 구성 편차가 발생하여 눈송이 서버가 되어 버린다.
  • 서버 생성 옵션을 스크립트에 넣는 방법 - 새 서버를 생성하는 절차를 간편하게 해 줌. 매번 편집해야 하는 스크립트는 피해야 함
  • 안티패턴:무중단 복제 서버 - 운영중인 서버를 복제하는 방법.서버 폭증에 따라 구성 편차와 관리의 어려움을 겪는 주된 이유는 서버를 복제하는 습관 때문. 한 대를 master로 지정하고 복제한다고 해도 그 상태는 지속적으로 달라짐.
  • 패턴:서버 템플릿 - 템플릿은 정적, 템플릿은 가동되지 않으므로 변경이나 데이터가 누적되지 않는다. 특정 템플릿으로 만든 두대의 서버는 일주일 간격으로 시작되었더라도 동일하나, 운영중인 서버를 복제하는 경우는 그렇지 않다.
  • 안티패턴 :눈송이 공장 - 새 VM생성시 사람이 구성 옵션을 변경하는 데 관여하게 되면, 서버들은 일관성을 잃게 된다. 서버를 계속 패치하고 업데이트하는 작업을 자동화하기 어려워짐.

코드에서 서버를 생성하는 방법

새 서버를 부트스트랩 하는 패턴

  • 밀어넣기 방식의 부트스트랩
    • 구성 서버를 사용하거나 별도 구성하는 방식, 중앙의 서버나 에이전트가 네트워크를 통해 새 서버에 SSH로 접속하여 작업을 전달함, 보안에 취약할 수 있음. 새 서버를 시작할 때 임시 인증 비번등을 생성하여 보안 취약점을 제거할 수 있음.
  • 끌어오기 방식의 부트스트랩
    • 새 서버 실행이 시작될 때 함께 실행되는 스크립트를 통해 서버를 구성하는 방식으로 동작. 구성 정의 파일을 저장소에서 내려받거나, 중앙 레지스트리에서 검색하거나, 파일 서버에서 최신 소프트웨어를 내려받아 구성할수도 있다.
  • 관례 : 모든 새 서버 인스턴스에 연기 시험을 하라.
    • 자동으로 생성한 서버는 자동으로 테스트 할 수 있다. 자동 연기 시험(Smoke Test) 스크립트를 통해 모든 서버의 기본적인 기능을 확인한다.(동작,접속여부,에이전트 기동여부, SW동작여부 등)

서버 템플릿을 관리하는 패턴

스톡 템플릿 : 다른 누군가 템플릿을 관리하게 할 수 없는가? -> AWS의 스톡 AMI와 같이 다른 누군가가 관리하는 템플릿을 사용

템플릿을 이용해 서버 프로비저닝하기

  • 생성 시점에 프로비저닝하기 - 템플릿에는 최소한만 담아 유지하고 생성 시점에 프로비저닝 작업 대부분을 하는 방법. 관리요건이 최소화(템플릿이 작으므로)되나 생성시 시간이 많이 소요된다.
  • 템플릿에 프로비저닝하기 - 프로비저닝할 것들 대부분을 템플릿에 넣는 방법, 빠르고 간단하게 새 서버를 생성할 수 있으나, 더 나은 절차와 도구가 필요(템플릿의 버전, 자동화 테스트 필요)
  • 템플릿과 생성 시점 프로비저닝 사이 균형 잡기

서버 템플릿을 만드는 절차

  • 다양한 플랫폼을 위한 템플릿 생성하기

서버 템플릿의 원본 이미지

  • 안티 패턴 : 무중단 복제한 서버 템플릿
  • OS 설치 이미지로 템플릿 굽기 - OS제조사에서 제공하는 깨끗한 이미지 기반
  • 스톡 이미지로 템플릿 굽기 - 클라우드 등에서 제공하는 작성된 이미지 기반, 보통은 다목적으로 만들어져 있으며, 불필요한 패키지는 걷어내는 게 좋다
  • 유니커널로 템플릿 만들기 - 단일 주소 공간에서 하나의 프로세스만 실행하려고 만든 이미지.
  • 부팅 없이 서버 템플릿 수정하기 - AWS의 AMI처럼 디스크 볼륨으로 붙여서 바로 수정할 수 있는 방법(템플릿 수정을 위해 띄우고, 굽는 방법은 오래 걸림)

JEOS(Just Enough Operating System)?

  • 시스템 이미지를 꼭 필요한 만큼 최소한으로 줄이자는 것
  • Redhat atomic, CoreOS, MS nano, Rancher OS, 스내피 우분투 코어, VMWare 포톤

서버를 업데이트하고 변경하는 패턴

서버 변경 관리 모형

  • 일시적 변경 관리 : 레거시
  • 지속적 구성 동기화 : 서버 구성도구를 이용한 변경
  • 불변 서버 : 완전히 새로운 서버를 만들어 서버를 변경하는 방식(구성은 불변이나, 실제 데이터나 로그는 불변이 아님, 구성으로 관리할 요소와 데이터로 관리할 요소를 분리해야 함)
  • 컨테이너화 된 서버
  • 패턴 : 피닉스 서버 - 서버 템플릿을 업데이트하지 않았을때에도 서버를 교체, 구성 편차를 방지하는 방법. 모든 서버에 최대 수명을 설정한 후 수명을 초과한 서버를 재생성.

지속적 배포를 위한 패턴과 관례

  • 밀어넣기 방식의 동기화,끌어오기 방식의 동기화
  • 패턴 : 마스터 없는 구성 관리 - 사용하는 구성도구가 중앙 서버를 지원하더라도, 중앙 서버를 없애는 것이 더 효과적(안정성, 가동시간, 확장성 개선), 방법은 구성 정의의 사본을 코드로 관리하며, 내려받은 후 구성 관리 도구를 오프라인 모드로 실행하는 것
  • 관례 : 서버의 수명이 유지되는 동안 동일한 구성 도구를 사용
  • 지속적 동기화 흐름
  • 동기화 미구성 영역

불변 서버를 위한 패턴과 관례

  • 불변 서버를 사용하면 구성관리도구의 부담이 줄어 간소화 할 수 있음. 구성관리도구는 지속하여 실행되도록 설계되어 있으며, 그래서 설계와 사용법이 복잡한 편임. 매번 새 서버 템플릿을 통해 생성된 서버에 적용하면 구성도구를 실행할 때 서버의 시작상태를 예측할 수 있음.
  • 불변 서버로 부트스트랩 구성하기
    • 새 템플릿을 만들 때 시간이 너무 오래 걸린다면, 새 서버를 부트스트랩 할 때 한두개의 요소를 추가하여 생성할 수 있음(생성시 전달할 구성 설정,시험용 애플리케이션 빌드와 같은) –> 서버 생성시 실행이 시작되는 시점에 애플리케이션 빌드를 가져와서 실행하는 방식은 마이크로서비스에 유용
  • 트랜잭션 서버 업데이트
  • 별도 패키지 관리 도구가 필요, 서버의 모든 패키지를 지정된 버전으로 업데이트하는 작업을 원자성 트랜잭션으로 지원해야 함.

구성 정의를 관리하는 관례

  • 관례 : 구성 정의는 최소한으로 유지하라 - 코드 크기가 커질수록 작성,관리,수정,테스트 부담이 커지므로, 코드의 크기를 최소화하도록 노력해야 한다. 가능하면 코드를 작성할 필요를 없애야 함. 자동화된 구성을 구현하는 좋은 방법은 가장 필요한 것들만 정의를 만들어 작게 시작하는 것
  • 구성 정의 구조화하기 - 서버 구성도구 안에서도 모듈화와 재사용을 위한 도구의 기능을 사용하는 방법을 배워야 한다.(Chef의 BerkShelf 처럼)
  • 관례 : 좋은 설계를 위해 TDD를 사용하라.

인프라를 정의하는 패턴

스택 - 하나의 단위로 정의된 인프라 요소들의 모음(AWS Cloudformation에서 따옴)

환경

  • 안티패턴 : 수제 인프라
  • 코드로 인프라 스택 정의하기
  • 안티패턴 : 환경별 정의 파일
  • 패턴 : 재사용 가능한 정의파일
  • 관례 : 스택 정의를 시험하고 전개하라
  • 셀프서비스 환경

인프라 구조화하기

  • 안티패턴 : 일체형 스택
  • 인프라를 ‘들어서 이동’하지 마라
  • 애플리케이션 환경을 여러 스택으로 나누기
  • 스택간의 구성 매개변수 관리하기 : 구성 레지스트리 등을 통해 중앙에 구성을 저장하고 스택간의 정보를 조율한다.
    • 경량 레지스트리를 사용한 스택간 구성 공유 : aws s3에서 json,yaml등을 가져와서 활용하는 정도로도 가능
  • 인프라 요소 공유하기 : 공유되는 인프라를 변경하는 것은 어려운 일
    • 관례: 어플리케이션 코드와 인프라 코드를 함께 관리하라
    • 정의를 공유하는 방법
    • 관례: 인프라 설계를 변경의 범위에 맞춰라

인프라를 위한 소프트웨어 엔지니어링 관례

  • 브랜치에서 작업하더라도 공유 줄기에 지속적으로 통합해야 한다.
  • 코드 품질 - 소프트웨어 개발과 동일하게 인프라 코드도 품질을 관리해야 한다.
  • 애자일 시험 방법 이용 - 변경 - 시험 - 수정 피드백 주기
    • 균형잡힌 시험체계 구현하기 - serverspec등으로 인프라 환경을 테스트
    • 하위수준 시험
      • 구문 점검, 정적 분석(puppet validate 등의 명령으로), 정적 코드 분석(puppet lint,chef의 food critic)
      • 단위 시험 - rspec-puppet, chef spec, salt의 자체 시험 도구 등
    • 중간수준 시험
      • 애플리케이션 서버 역할 시험 등 안에서의 중간단위 시험
      • 로컬 가상화 시험, 시험용 인프라를 통한 테스트 - testkitchen 등
    • 상위수준 시험 - 통합테스트, 외부 연계 테스트 등