Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

기술 뉴스 #99 : 18-04-01

웹개발 관련

  • Machine Learning-Driven Bundling. The Future of JavaScript Tooling : 웹페이지가 점점 복잡해짐에 따라 속도를 높이기 위해 Code Splitting을 하고 pre-fetch를 하는데 이를 Google Analytics에 쌓인 사용자가 방문한 페이지에 기반을 둬서 자동으로 이뤄질 수 있도록 한 접근이다. 아직 실험적이라고는 하지만 React와 Angular에 대한 데모를 다 제공하고 있고 GA 데이터를 분석해서 자동으로 Code Splitting을 하고 pre-fetch하는 모듈까지 만들어놨다. 정말 흥미로운 접근인데 앞으로는 이렇게 데이터를 이용해서 자동으로 번들링을 하게 될 것 같다.(영어)
  • 10x Performance Increases: Optimizing a Static Site : 해외에 나갔다가 자신의 사이트가 느리다는 것을 깨닫고 웹사이트를 개선한 과정을 설명한 글이다. 요청 수 줄이기, 압축, HTTP/2, 캐싱 등 웹사이트 성능에서 기본적이지만 필수적인 부분을 하나하나 다루고 있다.(영어)
  • How to NOT React: Common Anti-Patterns and Gotchas in React : React에서 주의해야 할 안티 패턴과 해결책을 설명한 글이다. 컴포넌트에서 bind() 함수의 사용, 이터레이터에서 key 값에 주의할 부분, setState()가 비동기라서 의도대로 안되는 부분, props로 클래스 생성자에서 값을 초기화할 때 이후 업데이트가 안 되는 부분 등을 다루고 있다.(영어)
  • How we gradually migrated to TypeScript at Unsplash : JavaScript로 작업하던 Unsplash에서 TypeScirpt로 전환한 과정을 설명한 글이다. 먼저 tsconfig.json를 추가해서 JS 파일의 타입 체커로 사용하고 코드에 JSDoc을 추가한 뒤에 순차적으로 JavaScript 코드를 TypeScript로 변환하면서 컴파일로 옵션을 점점 엄격하게 적용했다고 한다.(영어)
  • Top JavaScript VSCode Extensions for Faster Development : Visual Studio Code로 JavaScript 개발할 때 도움이 될 유용한 익스텐션을 정리한 글이다. REPL처럼 에디터 내에서 즉시 실행결과를 볼 수 있거나 여는 괄호와 닫는 괄호의 색을 맞춰서 보여주거나 import 할 때 해당 모듈의 크기를 보여주는 등 흥미로운 익스텐션이 많다.(영어)
  • Check out these useful ECMAScript 2015 (ES6) tips and tricks : ES2015에서 유용한 팁을 모아놓은 글이다. 기본 파라미터값을 이용한 필수값 검사와 reduce, 전개 연산자 사용법 등이 있는데 나같은 경우는 destructuring의 활용이 꽤 유용했다. ES2015를 사용하면 JavaScript 코드가 깔끔해지므로 몰랐던 내용이 있는지 확인해 볼 만하다.(영어)
  • Making WebAssembly better for Rust & for all languages : WebAssembly의 현재 제약사항으로 Rust 등의 언어를 사용해서 JavaScript와 같이 사용할 때의 접근 방법을 설명하는 글이다. wasm에 현재 integers와 floating point만 지원하므로 다른 타입을 wasm에 전달해서 주고받으려면 메모리에 저장한 뒤 숫자로 메모리 위치를 넘기는 등의 방법을 사용해야 하는데 wasm-bindgen를 이용해서 이를 간편하게 할 수 있고 wasm-pack를 이용해서 Rust 코드와 JS 코드를 같이 npm 모듈로 만들 수 있다. 그리고 JS와 wasm을 같이 사용하기 위해서 ES modules를 이용하는 방법까지 나와 있어서 현재 WebAssembly가 어느 정도 위치에 와있는지 파악할 수 있다.(영어)
  • Tomorrow’s ES Modules Today! : 아직은 Node.js에서 완전히 지원하지 않은 ES Modules를 바로 사용할 수 있게 만들어주는 ESM 모듈의 현재 상황과 방향을 얘기하는 글이다. CJS 기반인 Node.js에서 별다른 설정 없이 바로 ES Modules를 사용할 수 있으며 Node.js가 .mjs로 가려고 하고 있으므로 이 부분은 아직 활성화해놓지 않고 .jsrequire문 대신 import 문을 쓸 수 있게 해준다.(영어)

그 밖의 프로그래밍 관련

볼만한 링크

  • 나는 그저 그런 개발자입니다. : 그저 그런(?) 개발자가 살아남기 위해서 어떻게 하는 게 좋은지 본인의 경험을 바탕으로 정리한 글이다. 쉽게 읽을 수 있는 글이지만 좋은 공부 방법을 나와 있다.(한국어)
  • 회사에서 발견할 수 있는 50가지 유형의 사람들 대정리 : 회사에서 볼 수 있는 사람들의 유형을 정리한 글이다. 글을 꽤 재미있게 잘 써서 보면서 그래 이런 사람 있지 하면서 재미있게 읽었다.(한국어)
  • 개발자가 블로그를 운영해야 할 이유 : 개발 블로그가 더 많아지길 바라는 사람으로서 반가운 글이다. 블로그를 해야 하는 이유로 글을 쓰면서 더 정확한 지식을 얻을 수 있고 좋은 동기화 새로운 기회를 얻을 수 있고 운이 좋다면 부수입을 얻을 수 있는 점을 꼽았다. 오랫동안 블로그를 운영한 경험을 바탕으로 어떤 주제로 글을 쓰면 좋을지도 설명하고 있다.(한국어)
  • How to write a great developer résumé and showcase your software engineer skills : 개발자가 이력서를 작성할 때 해야 할 일과 하지 말아야 할 부분을 정리한 글이다. Twitter에 입사하면서 자신이 깨달은 부분과 입사 후에 Twitter의 기술 리크루터 Kristin Simmons와 논의해서 정리한 글이라 더 신뢰가 가고 국내와는 약간 다른 해외 시장을 보고 있다면 참고해 봐야 할 글이다.(영어)
  • 신입 소프트웨어 엔지니어의 영문 이력서 작성 후기 : 영문 이력서를 작성하면서 염두에 두어야 할 부분을 체크리스트로 정리해 놓았고 이를 바탕으로 글쓴이가 작성한 이력서를 첨부해 두고 단락마다 어떤 의도로 정리했는지가 잘 나와 있다. 정리가 잘 되어 있어서 영문 이력서를 작성하려고 할 때 읽어두면 도움이 될 글이다.(영어)
  • 1달 사용해 본 후 느낀 스팀잇의 문제점 5가지 : 블로그를 하다 보니 스팀잇에도 관심이 있는데 자세히 살펴본 적은 없지만, 이 글을 통해서 스팀잇의 분위기를 어느 정도 느낄 수 있었다. 주로 스팀파워를 가진 고래들에게 너무 편중된 파워의 차이와 좋은 글이 제대로 큐레이팅 되지 않고 오히려 특정 사람들의 글이나 수익이 높을 것이라고 예상되는 글만 추천을 받아서 타임라인이 재미없어지는 부분을 문제점으로 꼽았다.(한국어)

IT 업계 뉴스

프로젝트

  • TOAST UI Chart : NHN 엔터테인먼트에서 공개한 오픈소스 JavaScript 차트 라이브러리로 IE 8 이상을 지원한다.
  • oclif : Heroku에서 만든 Node.js CLI 프레임워크.
  • Dejavu : Elasticsearch의 웹 UI.
  • Babel Time Travel : Babel이 JavaScript 트랜스파일하는 과정을 단계별로 볼 수 있는 웹사이트.
  • TensorFlow.js : ML 모델을 훈련하고 배포하는 WebGL 기반의 JavaScript 라이브러리.

버전 업데이트

2018/04/01 19:25 2018/04/01 19:25

Google Cloud Platform에 Terraform 설정하기

그동안 Terraform을 주로 AWS에서 사용했는데 이번에 Kubernetes 스터디를 하면서 Kubernetes Engine을 사용해 보려고 하고 있다. 설치해서 운영하는 것도 궁금하기는 하지만 일단 Kubernetes Engine로 클러스터 운영을 보려고 하는데 요즘은 모든 클라우드를 Terraform으로 설정하기 때문에 Kubernetes Engine을 만들기 전에 Google Cloud Platform을 Terraform으로 관리하기 위한 설정이 필요했다.

Terraform으로 클라우드를 관리하려면 사실 클라우드에 대한 이해도가 높아야 한다. 다시 말하면 Terraform은 Infrastructure as Code로 관리되지 않던 인프라를 관리해 주지만 내부를 몰라도 되도록 추상화해주지는 않는다. 사실 웹 관리 콘솔을 사용하는 것보다 내부를 훨씬 더 잘 이해해야 한다. 하지만 Google Cloud Platform(GCP)에서 간단한 Google API 정도만 이용해 봤지 인프라를 이용해 본 적은 없다. 그래서 GCP의 개념 등은 잘 모른다. 그래서 이글에서 설명하는 내용도 Terraform 설정 방식에 관한 부분이고 GCP 자체에 대한 설명은 부족한 편이다.

Google Cloud Platform 프로바이더 설정

Google Cloud Console에서 먼저 프로젝트를 생성해야 한다. 물론 이미 있는 프로젝트를 사용해도 된다. GCP에 대해서 다 이해 못했지만 AWS와는 달리 모든 리소스가 프로젝트 하위에 포함되는 것으로 보인다. API를 사용할 때는 어색하지 않았는데 인프라를 생성할 때는 어색하게 느껴졌다.

Google Cloud Console에서 프로젝트 생성

여기서는 terraform-demo라는 이름으로 프로젝트를 만들었다. 이 프로젝트를 Terraform으로 사용하기 위해 인증 정보를 생성해야 한다.

Google Cloud Console에서 사용자 인증 정보 생성

[API 및 서비스] - [사용자 인증 정보]에서 "서비스 계정 키"로 새로운 사용자 인증 정보를 만든다.

Google Cloud Console에서 사용자 인증 정보 설정

"새 서비스 계정"에서 이름을 입력하고 역할을 프로젝트 "소유자"로 지정했다. 이 역할에 대해서는 아직 완전히 이해는 못했는데(뒤에서 어차피 또 API 권한 설정을 해야 한다.) Terraform 같은 경우 해당 클라우드 프로바이더의 거의 모든 것을 제어할 수 있어야 하므로 모든 권한을 가질 수 있는 "소유자" 지정했다. 키 유형을 JSON으로 지정하고 생성하면 terraform-demo-f36db3369c3a.json 같은 파일이 다운로드 되는데 이 파일이 인증키이고 다음과 같이 생겼다.

{
  "type": "service_account",
  "project_id": "terraform-demo-123456",
  "private_key_id": "asdf123456",
  "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXX\n-----END PRIVATE KEY-----\n",
  "client_email": "terraform@terraform-demo-123456.iam.gserviceaccount.com",
  "client_id": "111222333444",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/terraform%40terraform-demo-123456.iam.gserviceaccount.com"
}

이 인증키를 Terraform을 사용하는 폴더로 이동하고 다음과 같은 providers.tf를 생성한다.

provider "google" {
  version     = "~> 1.8"
  credentials = "${file("terraform-demo-f36db3369c3a.json")}"
  project     = "terraform-demo-123456"
  region      = "asia-northeast1"
}

이는 Terraform의 Google Cloud Provider 설정이다. versionsterraform-provider-google의 버전을 지정한 것이다. 꼭 필수는 아닌데 하위 프로바이더와 동작하지 않도록 보통은 지정하는 편이다. credentials은 앞에서 다운로드받은 인증키 파일의 위치를 지정해 준 것이다. projectregion은 꼭 지정하지 않아도 되는데 Terrafom으로 계속 관리하다 보니까 문제가 생기는 경우가 있어서 문서에 나온 대로 그냥 지정했다. project는 인증키 파일에도 있는데 굳이 또 지정해야 하는 이유는 모르겠고 리전 정보는 GCP 문서에서 찾을 수 있다.

$ terraform init

Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "google" (1.8.0)...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Terraform을 초기화하고 프로바이더 플러그인을 가져왔다.

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

------------------------------------------------------------------------

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.

plan을 실행해보면 정상적으로 실행되는 것을 알 수 있다.

Terraform Remote Backend 설정

Terraform의 상태 파일인 .tfstate 파일은 로컬보다는 원격에서 관리해야 하므로 GCP에서도 마찬가지로 Google Cloud Storage(GCS)를 리모트 백엔드로 설정해서 tfstate를 관리하기 위해 GCS 설정부터 해야한다.

gcs.tf라는 파일을 만들어 보자.

resource "google_storage_bucket" "terraform_state" {
  name     = "outsider-terraform-demo-state"
  location = "asia-northeast1"

  versioning = {
    enabled = "true"
  }
}

GCS에서 버킷을 생성하는 설정이다. 여기서 이름은 S3처럼 전 사용자가 공통으로 쓰는지 일반적인 이름은 사용 중이라고 충돌 나므로 접두사를 붙여주는 게 좋다. tfstate를 관리할 것이므로 vserioning도 활성화 했다. terraform plan을 실행하면 정상적으로 나오지만, 막상 apply를 하려고 하면 다음과 같이 권한 오류가 발생한다.

* google_storage_bucket.terraform_state: googleapi: Error 403: Access Not Configured. Compute Engine API has not been used in project 12345678 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=12345678 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry., accessNotConfigured

저 URL에 나온 대로 API 사용 권한을 주어야 한다. 여기서는 "Google Compute Engine API"를 사용으로 설정해야 한다.

Google Compute Engine API 사용 설정

이제 다시 적용하면 정상적으로 GCS에 버킷이 생성된다.

$ terraform apply

google_storage_bucket.terraform_state: Creating...
  force_destroy:        "" => "false"
  location:             "" => "ASIA-NORTHEAST1"
  name:                 "" => "outsider-terraform-demo-state"
  project:              "" => "<computed>"
  self_link:            "" => "<computed>"
  storage_class:        "" => "STANDARD"
  url:                  "" => "<computed>"
  versioning.#:         "" => "1"
  versioning.0.enabled: "" => "true"
google_storage_bucket.terraform_state: Creation complete after 5s (ID: outsider-terraform-demo-state)

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

생성된 GCS 버킷

리소스가 잘 생성되었으므로 이 내용을 기록하고 있는 terraform.tfstate 파일이 로컬에 생성된다. 이 파일을 이제 여기서 만든 GCS에서 관리하도록 올려야 한다. terraform.tf파일을 다음의 내용으로 작성한다.

terraform {
  required_version = ">= 0.11.5"

  backend "gcs" {
    bucket = "outsider-terraform-demo-state"
    prefix = "terraform-demo"
    region = "asia-northeast1"
  }
}

여기서 bucket은 앞에서 만든 GCS의 버킷이고 여러 tfstate를 관리하게 될 가능성이 크므로 prefix를 붙였다. 리모트 백엔드를 추가하면 다시 terraform init을 해야 한다.

$ terraform init

Initializing the backend...

Error configuring the backend "gcs": storage.NewClient() failed: dialing: google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.

Please update the configuration in your Terraform files to fix this error
then run this command again.

하지만 이를 실행하면 위처럼 오류가 발생한다. 오류의 내용을 보면 기본 인증을 찾을 수 없다고 나오는데 문서를 보면 Application Default Credentials(ADC)라고 GCP 클라이언트가 사용하는 기본 인증정보로 보인다. 이를 설정하는 GOOGLE_APPLICATION_CREDENTIALS 환경변수에 관해 Terraform 문서에도 나와 있어서 이를 바탕으로 GOOGLE_APPLICATION_CREDENTIALS 환경변수를 설정했다. 이 값은 앞의 providers.tf에서 설정한 JSON 파일과 같다.

$ export GOOGLE_APPLICATION_CREDENTIALS=terraform-demo-f36db3369c3a.json

이제 다시 terraform init를 실행해보자.

$ terraform init

Initializing the backend...
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "gcs" backend. An existing non-empty state already exists in
  the new backend. The two states have been saved to temporary files that will be
  removed after responding to this query.

  Previous (type "local"): /var/folders/k8/j1j0fjkn5_vdzxybfqq0r7lc0000gn/T/terraform300035322/1-local.tfstate
  New      (type "gcs"): /var/folders/k8/j1j0fjkn5_vdzxybfqq0r7lc0000gn/T/terraform300035322/2-gcs.tfstate

  Do you want to overwrite the state in the new backend with the previous state?
  Enter "yes" to copy and "no" to start with the existing state in the newly
  configured "gcs" backend.

  Enter a value: yes


Successfully configured the backend "gcs"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

정상적으로 실행되면서 로컬에 있는 tfstate를 GCS에 업로드할 것인지를 묻고 yes를 입력하면 GCS를 리모트 백엔드로 사용하도록 설정한다. 이제 로컬에서는 tfstate를 지워도 되고 테스트를 해보면 Lock도 제대로 동작하는 것을 알 수 있다.

GCS에 올라간 tfstate 파일

GCS에 들어가 보면 default.tfstate라는 파일로 올라간 것을 확인할 수 있다.

2018/03/31 15:42 2018/03/31 15:42