Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

GitHub Codespaces의 개발 환경 설정하기

GitHub Codespaces 베타를 받아서 틈틈이 살펴보고 있는데 전에는 문서까지 다 읽어보지는 않고 그냥 온라인 VS Code로 생각하고 바로 사용하면서 테스트만 해봤는데 좀 더 살펴보다 보니 Codespaces 환경을 필요에 따라 설정할 수 있다는 것을 알게 되었다. 개발환경을 생각하면 사용하는 포트도 다르고 데이터베이스 같은 다른 서비스도 필요하니까 어찌 보면 당연한 얘기인데 실제 개발에 안 쓰고 테스트만 다 보니 미처 생각하지 못했다.

GitHub의 Codespaces는 GitHub 쪽에도 문서가 있지만 실제로는 Visual Studio Codespaces에서 넘어온 것이기 때문에 참고 문서를 보면 VS Code 쪽 문서도 계속 나온다. 커스터마이징 하지 않으면 Node.js, JavaScript, TypeScript, Python, C++, Java, C#, .NET Core, PHP, PowerShell을 위한 도구가 포함된 기본 Linux 이미지가 사용된다.

Codespaces 환경 설정

저장소 루트에 devcontainer.json 파일을 두거나 .devcontainer 폴더 아래 devcontainer.json 파일 및 추가 파일을 두어서 Codespace 환경을 원하는 대로 만들 수 있다. vscode-dev-containers 저장소에서 언어별 샘플 설정을 제공하고 있어서 원하는 컨테이너를 골라서 .devcontainer를 자신의 폴더로 가져가면 된다.

간단히 커스텀 환경을 생성해 보자. 프로젝트 루트 디렉터리에 .devcontainer 디렉터리를 만들고 그 아래 devcontainer.json 파일을 만들어서 다음과 같이 설정한다.

{
  "name": "Node.js project",
  "workspaceFolder": "/workspace",

  "build": {
    "dockerfile": "Dockerfile"
  },

  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash"
  },

  "extensions": [
    "dbaeumer.vscode-eslint",
  ],

  "forwardPorts": [3000],

  "postCreateCommand": "npm install",

  "remoteUser": "node"
}

내가 지정한 Docker 컨테이너에 필요한 몇 가지 설정을 한 간단한 구성이다. 각 설정에 대한 자세한 내용은 devcontainer.json reference에서 볼 수 있다. 중요한

  • name: 컨테이너 이름
  • extensions: 생성될 때 설치할 익스텐션
  • settings: settings.json에 추가될 설정
  • forwardPorts: 컨테이너 포워딩할 포트
  • postCreateCommand: 생성된 후 컨테이너 내에서 실행할 명령어
  • image: DockerHub나 Azure Container Registry의 컨테이너 이미지 이름으로 공개 이미지만 가능하다.
  • build.dockerfile: Dockerfile을 직접 지정해서 사용하고 상대 경로로 지정한다.
  • build.context: Docker 빌드가 실행될 경로
  • build.args: Docker 이미지 빌드 인자
  • containerEnv: 컨테이너의 환경 변수
  • remoteEnv: VS Code의 환경 변수
  • containerUser: 컨테이너의 사용자 명
  • remoteUser: VS Code의 사용자 명

이제 앞에서 build.dockerfile로 지정한 .devcontainer/Dockerfile을 생성하자.

ARG VARIANT=14
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT}

Codespace를 생성해서 확인해 보면 설정에 지정한 Node 버전과 사용자명으로 설정된 것을 알 수 있다.

터미널에서 node 버전이 v14.14.0이고 사용자 계정이 node

이전에 터미널에서 서버를 띄우거나 할 때 설정해 주어야 했던 포트 포워딩도 미리 설정된 것을 알 수 있다. 어차피 프로젝트에서 사용하는 포트는 정해져 있으니 미리 설정해 두면 편하게 사용할 수 있다.

Forwarded ports에 이미 3000포트가 설정됨

주로 사용하는 익스텐션도 지정한 대로 설정되어서 실행된 것을 알 수 있다.

설치된 익스텐션에 ES Lint 익스텐션이 자동 설치됨

물론 이 .devcontainer의 설정을 변경하면 이미 생성한 Codespace도 자동으로 바뀌진 않고 새로 생성해야 한다.

Docker Compose 이용하기

Docker로 원하는 환경을 구성할 수 있지만, 실제 프로젝트를 생각하면 데이터베이스나 캐시서버 등 개발에 필요한 다른 서비스가 많이 필요하다. 개발환경을 구성하기 위해 Docker Compose를 많이 이용하곤 하는데 이를 Codespace에서도 사용할 수 있다.

이 설정은 VS Code에서 제공하는 Node.js & PostgreSQL 예제를 참고해서 작성했다.

.devcontainer/devcontainer.json 파일을 생성한다.

{
  "name": "Node.js & PostgreSQL",
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "workspaceFolder": "/workspace",

  "extensions": [
    "dbaeumer.vscode-eslint",
    "mtxr.sqltools",
    "mtxr.sqltools-driver-pg"
  ],

  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash",
    "sqltools.connections": [{
      "name": "Container database",
      "driver": "PostgreSQL",
      "previewLimit": 50,
      "server": "localhost",
      "port": 5432,
      "database": "postgres",
      "username": "postgres",
      "password": "postgres"
    }]
  },

  "forwardPorts": [3000, 5432],

  "remoteEnv": {
    "DATABASE_URL": "postgres://postgres:postgres@localhost:5432/postgres",
  },

  "remoteUser": "node"
}

앞과 다른 부분을 설명하자면

  • Dockerfile 대신 dockerComposeFile을 지정했다.
  • SQL 쿼리를 할 수 있도록 sqltools 익스텐션을 설치했다.
  • settings에서 DB에 접속할 수 있는 정보를 sqltools 익스텐션에 설정했다.
  • forwardPorts에서 Postgres의 포트를 열었다. 이는 로컬에서 Codespace에 띄워 놓은 데이터베이스에 접속하는 경우를 위해서 연 것이다.
  • "service": "app"은 Docker Compose로 실행한 서비스에서 VS Code가 어떤 서비스에 접속할까 하는 것이다.
  • remoteEnv에서 개발에 사용할 환경 변수를 설정했다.

앞에서 지정한 .devcontainer/docker-compose.yml 파일을 생성한다.

version: '3'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        VARIANT: 12
        USER_UID: 1000
        USER_GID: 1000

    volumes:
      - ..:/workspace:cached

    command: sleep infinity

    network_mode: service:db

  db:
    image: postgres:latest
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - 5432:5432
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres

volumes:
  postgres-data:

위에서 개발에 메인으로 사용할 app 서비스를 생성하고 여기서 Node를 12 버전으로 지정했고 postgres에 localhost로 접속할 수 있도록 network_mode: service:db를 설정했다. VS Code의 예제에는 ports:로 포트를 여는 부분이 없었는데 이러니 접속이 되지 않아서 추가했다.

Docker Compose에서 사용할 .devcontainer/Dockerfile을 생성하자.

ARG VARIANT=12
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:${VARIANT}

# Update args in docker-compose.yaml to set the UID/GID of the "node" user.
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \
        groupmod --gid $USER_GID node \
        && usermod --uid $USER_UID --gid $USER_GID node \
        && chown -R $USER_UID:$USER_GID /home/node \
        && chown -R $USER_UID:root /usr/local/share/nvm /usr/local/share/npm-global; \
    fi

여기선 사용자 설정만 있지만, 이 Docker 컨테이너에서 Codespace가 실행되므로 필요한 도구가 있으면 설치하면 된다.

sqltools 익스텐션에서 데이터베이스에 접속함

자동으로 설치된 sqltools 익스텐션에 설정한 커넥션도 생성되어 있음으로 바로 접속할 수 있다. 쿼리를 실행하면 잘 접속된 걸 알 수 있다.

지정한 node.js 버전과 환경변수가 출력됨

Dockerfile에서 설정한 대로 Node.js v12가 설치되어 있고 환경변수도 잘 설정된 것을 알 수 있다.

팀의 공통 개발환경으로 사용해도 좋을 듯...

전에 얘기한 대로 온라인에서 코딩할 생각은 별로 없지만, 프로젝트 개발 환경 설정을 포함해서 VS Code의 환경까지 설정하다 보니 훨씬 매력적으로 느껴졌다.

회사에서 생각하면 새로 들어온 사람이나 참여 안 하던 프로젝트에 갑자기 개발하려면 로컬에서 개발환경 구성하느라고 많은 시간을 허비하게 된다. 팀에 따라 Docker Compose로 설정해서 이 문제를 해결하기도 하지만 Codespaces를 사용한다면 각자가 환경을 실행만 한다면 바로 팀원 모두가 공통된 개발환경을 이용할 수 있다는 점은 꽤 매력적으로 느껴진다. 난 VS Code가 메인 IDE가 아니기 때문에 IDE의 선택권의 자유가 없다는 부분은 불편하게 느껴지지만 대신 얻을 수 있는 장점이 확실히 있게 느껴진다.

2020/11/09 23:00 2020/11/09 23:00