Featured Post

20년 개발자도 이제야 제대로 반한 Devcontainer, 개발환경 세팅 스트레스가 확 줄었어요

Devcontainer - 개발환경 관련 이미지

요즘 개발하다 보면 Devcontainer 이야기, 한 번쯤은 들리잖아요. 저도 처음엔 솔직히 좀 시큰둥했어요. “아, 또 Docker 기반으로 뭔가 감싼 거겠지” 하는 마음이었거든요. 그런데 최근 사이드 프로젝트를 하나 하면서 팀원들끼리 개발 환경 때문에 꽤 피곤한 시간을 보냈어요. 제 맥북에서는 멀쩡히 도는데, 다른 팀원 윈도우에서는 패키지 설치부터 꼬이고, WSL2 경로 문제 나오고, Python 버전 미묘하게 다르고요. 이런 상황이 몇 번 반복되니까 뭐랄까, 코드 짜기도 전에 체력이 먼저 빠지더라고요.

그래서 이번에는 마음먹고 Devcontainer를 제대로 써봤습니다. 예전처럼 “좋다더라” 수준이 아니라, 실제 팀 프로젝트에 넣고 신입 개발자 온보딩까지 해봤어요. 결과는 꽤 인상적이었습니다. 아니, 좀 과장해서 말하면 “내가 이걸 왜 이제야 진지하게 봤지?” 싶었어요. 오늘은 20년 넘게 개발하면서 환경 세팅에 여러 번 데여본 직장인 개발자 입장에서, 제가 실제로 써보고 느낀 Devcontainer 활용법LLM 코딩 환경에서 토큰을 아끼는 설정 이야기를 편하게 풀어볼게요.

Devcontainer가 그냥 Docker랑 뭐가 다르냐고 물어본다면

사실 Docker로 개발 환경을 맞추는 건 예전부터 많이 했죠. 저도 오래전부터 프로젝트마다 Dockerfile 만들고, docker-compose.yml 정리하고, README에 실행 방법 적어두고 그랬어요. 그런데 막상 팀원이 새로 들어오면 꼭 어딘가에서 삐끗합니다. 포트가 이미 사용 중이거나, 볼륨 마운트 권한이 꼬이거나, 로컬에 깔린 Node.js 버전이 이상하거나요. 이런 건 문서에 아무리 잘 적어놔도 결국 누군가는 한 번씩 밟더라고요.

Devcontainer는 그 불편함을 IDE 안으로 꽤 자연스럽게 끌고 들어옵니다. 핵심은 VS CodeJetBrains 같은 개발 도구와 개발 컨테이너가 연결된다는 점이에요. 예전에는 터미널에서 컨테이너 띄우고, 포트 확인하고, IDE에서 인터프리터 다시 잡고, 디버거 연결하고 그랬잖아요. Devcontainer를 쓰면 .devcontainer/devcontainer.json 하나를 기준으로 IDE가 컨테이너를 열어주고, 그 안에서 바로 코드를 만질 수 있습니다. 느낌이 좀 다릅니다. “컨테이너 위에서 작업한다”기보다 “내 로컬 개발환경이 컨테이너로 바뀌었다”에 가까워요.

제가 가장 크게 체감한 건 팀 온보딩 시간이었어요. 예전에는 새로 합류한 분에게 이런 식으로 안내했거든요.

    • Node.js 18 설치해주세요.
    • Python은 3.11로 맞춰주세요.
    • Redis는 Docker로 띄우면 됩니다.
    • PostgreSQL 포트는 5432인데 이미 쓰고 있으면 바꿔야 해요.
    • pre-commit 설치하고 한 번 실행해주세요.
    • 아, macOS면 brew로 이거 하나 더 설치해야 합니다.

이렇게 말하고 나면 듣는 사람도 지치고, 설명하는 사람도 슬슬 미안해집니다. 개발을 시작하기도 전에 벌써 피곤한 거죠. 그런데 Devcontainer를 붙인 뒤에는 안내가 훨씬 단순해졌어요.

“레포 클론하고, VS Code로 열고, Reopen in Container 누르면 돼요.”

이 한 문장이 진짜 편하더라고요. 실제로 팀에 새로 들어온 개발자 한 분이 첫날 오전에 환경 세팅 끝내고 바로 작은 버그를 잡았습니다. 예전 같았으면 최소 반나절, 운 나쁘면 하루는 그냥 날아갔을 상황이었어요. 이런 경험을 한 번 하고 나니까 Devcontainer를 그냥 유행하는 도구로 보기 어렵더라고요. 이건 팀의 시간을 아껴주는 장치에 가깝습니다.

내가 실제로 쓰는 Devcontainer 구성 기준

그렇다고 Devcontainer를 쓰기만 하면 다 좋아지는 건 아니에요. 아무 생각 없이 이것저것 다 넣으면 오히려 느려지고 복잡해집니다. 특히 요즘처럼 GitHub Copilot, Cursor, Claude Code 같은 도구를 함께 쓰는 환경에서는 더 조심해야 해요. 컨테이너 안에 불필요한 확장 기능과 의존성이 많아질수록 IDE도 무거워지고, LLM이 참고하는 컨텍스트도 지저분해집니다. 쉽게 말하면, AI에게 보여줄 필요 없는 짐을 잔뜩 들려주는 셈이에요.

저는 Devcontainer를 만들 때 최대한 작게 시작해서 필요한 것만 추가하는 쪽을 좋아합니다. 예전엔 “혹시 모르니까 다 넣자” 스타일이었는데, 개발 경력이 쌓일수록 그게 별로 좋은 습관이 아니라는 걸 알게 되더라고요. 여행 갈 때도 그렇잖아요. 예전엔 캐리어에 별걸 다 넣고 갔는데, 요즘은 진짜 입을 옷과 충전기만 챙기는 게 편합니다. 개발환경도 비슷해요. 가벼울수록 오래 갑니다.

제가 자주 쓰는 devcontainer.json 핵심 설정

설정 항목 실제로 쓰는 값 제가 이렇게 두는 이유
image mcr.microsoft.com/devcontainers/python:3.11 공식 이미지라 업데이트가 빠르고, 기본 도구 구성이 안정적입니다.
features "ghcr.io/devcontainers/features/docker-in-docker:2" 컨테이너 안에서 Docker가 꼭 필요할 때만 넣습니다. 아니면 과감히 빼요.
extensions ["ms-python.python", "ms-toolsai.jupyter"] 확장은 적을수록 좋았습니다. 꼭 필요한 것만 넣어야 시작도 빠르고 LLM 추천도 덜 산만해요.
forwardPorts [8000, 5432] 실제로 쓰는 포트만 열어둡니다. 괜히 많이 열어둘 이유가 없더라고요.

여기서 제가 제일 신경 쓰는 건 extensions입니다. 예전엔 VS Code 확장을 거의 종합선물세트처럼 넣어뒀어요. Python, Docker, YAML, Markdown, REST Client, GitLens, ESLint, Prettier, Jupyter, Terraform, Kubernetes까지요. “언젠가 쓰겠지” 싶은 마음이었는데, 막상 컨테이너 시작할 때마다 확장 설치하느라 시간이 꽤 걸렸습니다.

더 불편했던 건 LLM 기반 자동완성이었습니다. 확장이 많으니 언어 서버도 많이 뜨고, 프로젝트와 별 상관없는 파일에서도 추천이 튀어나오더라고요. 저는 이게 은근히 집중력을 갉아먹는다고 봐요. 추천이 많다고 생산성이 올라가는 게 아니거든요. 필요한 순간에 정확히 나오는 게 좋습니다.

지금은 프로젝트마다 확장을 아주 좁혀서 넣습니다. FastAPI 프로젝트라면 보통 ms-python.pythonhumao.rest-client 정도면 충분했어요. 데이터 분석 프로젝트면 거기에 ms-toolsai.jupyter를 추가하고요. 이렇게 바꾸고 나니 제 환경 기준으로 컨테이너 시작 시간이 대략 30초대에서 10초대 초반까지 줄었습니다. 숫자로 보니 별것 아닌 것 같지만, 하루에 여러 번 컨테이너를 열고 닫는 날에는 꽤 크게 느껴집니다.

LLM 코딩할 때 Devcontainer가 더 빛나는 지점

요즘은 저도 AI 도움 없이 코딩하는 시간이 많이 줄었습니다. GitHub Copilot도 쓰고, 상황에 따라 Cursor도 켜고, 복잡한 설계나 리팩터링은 LLM에게 초안을 부탁하기도 해요. 이걸 누가 게으르다고 할 수도 있겠지만, 저는 생각이 좀 다릅니다. 반복적인 걸 빨리 넘기고, 사람이 더 중요한 판단에 시간을 쓰는 게 맞다고 봐요. 다만 AI를 잘 쓰려면 주변 정리가 필요합니다. 책상이 엉망이면 일도 느려지듯이, 개발환경이 엉망이면 AI 추천도 자꾸 삐끗합니다.

Devcontainer는 이 부분에서 꽤 좋은 기반이 됩니다. 프로젝트마다 Python 버전, Node.js 버전, 시스템 패키지, 포트, VS Code 설정이 고정되니까 LLM이 바라보는 환경도 한결 일정해져요. 특히 팀원 전체가 같은 컨테이너에서 개발하면 “내 환경에서는 되는데요?”라는 말이 확 줄어듭니다. 이 말, 개발자끼리는 농담처럼 하지만 사실 들을 때마다 좀 피곤하잖아요.

postCreateCommand로 의존성 설치를 미리 끝내두기

제가 거의 습관처럼 넣는 설정이 postCreateCommand입니다. 컨테이너가 처음 만들어질 때 필요한 패키지를 한 번에 설치해두는 거예요.

"postCreateCommand": "pip install --no-cache-dir -r requirements.txt && pre-commit install"

이 설정 하나만 잘 넣어도 꽤 편해집니다. 컨테이너가 뜨고 나서 “아 맞다, requirements 설치해야지” 하고 터미널을 여는 일이 줄어요. 팀원도 똑같은 상태에서 시작하고요. 특히 LLM 코딩할 때는 이게 생각보다 중요합니다. 의존성이 설치되어 있으면 IDE가 import 경로를 제대로 잡고, 타입 힌트나 자동완성도 더 안정적으로 동작합니다. 그러면 Copilot이나 Cursor의 추천도 덜 뜬금없어져요.

제가 한 번은 이걸 빼먹은 상태로 FastAPI 코드를 계속 작성한 적이 있어요. 컨테이너 안에 일부 패키지가 안 깔려 있으니 IDE가 import 에러를 계속 보여줬고, LLM도 엉뚱한 대체 코드를 추천하더라고요. 나중에 보니 코드 문제가 아니라 환경 문제였습니다. 이런 건 참 허탈해요. 한참 헤매고 나서 “아, 설치를 안 했네” 하는 순간 말이죠.

Dockerfile은 작게, 하지만 필요한 시스템 패키지는 확실하게

기본 이미지로 충분한 프로젝트도 많지만, 가끔은 시스템 패키지가 꼭 필요합니다. 저는 영상 처리 쪽 프로젝트에서 ffmpeg가 필요했고, 다이어그램 생성 때문에 graphviz가 필요했던 적도 있어요. 이런 건 Python 패키지만 설치한다고 해결되지 않더라고요.

FROM mcr.microsoft.com/devcontainers/python:3.11

RUN apt-get update && apt-get install -y --no-install-recommends \
    ffmpeg \
    graphviz \
    && rm -rf /var/lib/apt/lists/*

이렇게 .devcontainer/Dockerfile을 하나 만들고, devcontainer.json에서 연결해주면 됩니다. 여기서 제가 꼭 챙기는 건 --no-install-recommends와 apt 캐시 삭제예요. 별것 아닌 것 같지만 차이가 큽니다.

예전에 이 옵션을 안 넣고 대충 설치했다가 이미지 크기가 2GB를 넘어간 적이 있습니다. 처음엔 “요즘 디스크도 큰데 뭐” 싶었는데, 팀원들이 컨테이너를 새로 빌드할 때마다 시간이 늘어나고, CI에서도 캐시가 꼬이기 시작하니 결국 제 잘못이더라고요. 그 뒤로는 Dockerfile을 쓸 때마다 조금 더 까다롭게 봅니다. 필요한 것만 넣고, 설치 후에는 정리하고, 레이어도 가능하면 단순하게 유지합니다.

VS Code 설정도 프로젝트 안에 같이 넣어두기

이건 제가 써보고 꽤 만족한 부분인데요. devcontainer.json 안에 VS Code 설정을 같이 넣어둘 수 있습니다. 팀 프로젝트에서는 이게 생각보다 효과가 좋아요. 누군가는 저장할 때 포맷팅이 되고, 누군가는 안 되고, 누군가는 import 정리가 되고, 누군가는 안 되면 코드 리뷰에서 쓸데없는 diff가 많이 생기거든요.

"settings": {
    "editor.inlineSuggest.enabled": true,
    "github.copilot.enable": {
        "*": true,
        "yaml": false,
        "markdown": false
    },
    "[python]": {
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.organizeImports": "explicit"
        }
    }
}

여기서 제가 은근히 좋아하는 설정은 github.copilot.enable 부분입니다. 저는 YAML이나 Markdown에서는 Copilot을 꺼두는 편이에요. 물론 문서 초안 쓸 때는 도움을 받을 수도 있지만, 설정 파일에서는 AI 추천이 오히려 방해될 때가 많았습니다. 특히 Kubernetes YAML이나 GitHub Actions 파일 만질 때, 맥락을 살짝 잘못 읽은 추천이 들어오면 괜히 확인할 게 늘어나요.

그래서 저는 코드 파일에서는 적극적으로 켜두고, 설정 파일이나 문서 파일에서는 조금 절제하는 쪽을 선택했습니다. 이건 사람마다 다를 수 있는데, 제 기준에서는 훨씬 편했어요. AI가 늘 옆에서 말 걸어주는 것도 좋지만, 가끔은 조용히 있어주는 게 더 고마울 때가 있거든요.

토큰을 아끼는 Devcontainer 사용 습관

LLM을 쓰다 보면 결국 토큰 이야기를 안 할 수가 없습니다. 특히 Cursor나 Claude 계열 도구를 쓰다 보면 프로젝트 전체를 컨텍스트로 넣거나, 여러 파일을 한 번에 물어보는 일이 많잖아요. 이때 개발환경이 정리되어 있으면 AI에게 설명할 말이 줄어듭니다. 반대로 환경이 뒤죽박죽이면 매번 “이 프로젝트는 Python 3.11이고, Redis가 필요하고, Postgres는 이런 버전이고...” 같은 설명을 반복하게 돼요. 이게 다 토큰이고, 결국 돈이고, 시간입니다.

제가 실제로 효과를 본 습관은 이런 것들이었습니다.

    • README에 환경 설명을 길게 쓰기보다 Devcontainer 설정으로 고정하기
      문서가 길면 사람도 안 읽고, LLM에게도 매번 설명해야 합니다. 실행 가능한 설정 파일이 더 낫습니다.
    • 확장 기능은 프로젝트에 필요한 것만 넣기
      언어 서버와 자동완성 소스가 많아지면 추천이 산만해지고, IDE도 무거워집니다.
    • 불필요한 샘플 파일과 오래된 실험 코드는 별도 폴더로 빼기
      LLM이 참고하지 않아도 될 파일을 계속 훑게 만들 필요가 없습니다.
    • .dockerignore와 .gitignore를 꼼꼼히 관리하기
      node_modules, .venv, dist, build 같은 폴더가 컨텍스트에 섞이면 빌드도 느리고 AI 분석도 지저분해집니다.
    • 프로젝트 규칙은 짧게, 하지만 명확하게 남기기
      예를 들어 “API 응답은 항상 Pydantic 모델을 사용한다” 같은 룰은 길게 설명하는 것보다 짧게 고정해두는 게 좋았습니다.

아래처럼 프로젝트 구조를 조금만 정리해도 LLM에게 전달하는 컨텍스트가 훨씬 깔끔해졌습니다.

project-root/
├── .devcontainer/
│   ├── devcontainer.json
│   └── Dockerfile
├── app/
│   ├── api/
│   ├── core/
│   └── services/
├── tests/
├── scripts/
├── requirements.txt
├── .dockerignore
└── README.md

뭔가 대단한 구조는 아니죠. 그런데 이런 기본기가 LLM 코딩에서는 꽤 중요합니다. AI에게 “대충 알아서 해줘”라고 말하면 정말 대충 합니다. 대신 프로젝트가 단정하고 규칙이 보이면, 추천도 훨씬 안정적으로 나와요. 저는 이걸 몇 번 경험하고 나서부터 새 프로젝트를 만들 때 폴더 구조와 Devcontainer부터 잡습니다. 코드보다 집터를 먼저 다지는 느낌이랄까요.

제가 Devcontainer 쓰면서 제대로 삽질했던 부분

물론 처음부터 순탄했던 건 아닙니다. 저도 처음에는 “좋다니까 모든 프로젝트에 다 넣어보자” 하고 달려들었어요. 그런데 이게 무조건 정답은 아니더라고요. 간단한 스크립트 하나 고치려고 Devcontainer를 빌드하고 있으면, 어느 순간 현타가 옵니다. 배보다 배꼽이 커진 느낌이죠.

그래서 지금은 프로젝트 성격에 따라 다르게 씁니다.

프로젝트 유형 Devcontainer 사용 여부 제 판단 기준
팀 프로젝트 거의 사용 사람마다 환경이 달라지는 비용이 훨씬 큽니다.
마이크로서비스 적극 사용 서비스별 런타임과 포트가 달라서 고정해두는 편이 낫습니다.
복잡한 웹 앱 사용 추천 DB, Redis, 백엔드, 프론트엔드가 얽히면 로컬 세팅이 쉽게 꼬입니다.
개인 토이 프로젝트 상황 봐서 사용 나중에 다시 열어볼 프로젝트라면 넣어두는 편이 좋았습니다.
단순 스크립트 잘 안 씀 간단한 작업은 로컬에서 바로 고치는 게 더 빠릅니다.

또 하나 크게 삽질했던 건 볼륨 마운트였습니다. 처음엔 “그냥 로컬 폴더 전체를 컨테이너에 연결하면 되겠지” 하고 단순하게 생각했어요. 그런데 node_modules.venv 같은 폴더가 로컬 환경과 컨테이너 환경에서 충돌하더라고요. 특히 macOS에서 설치된 패키지와 Linux 컨테이너 안에서 설치된 패키지가 섞이면 아주 묘한 에러가 납니다. 에러 메시지도 불친절해요.

그래서 지금은 공유해야 할 폴더만 명시적으로 마운트합니다.

"mounts": [
    "source=${localWorkspaceFolder}/data,target=/workspace/data,type=bind",
    "source=${localWorkspaceFolder}/.devcontainer/bash_history,target=/home/vscode/.bash_history,type=bind"
]

여기서 bash_history 공유는 꽤 소소한 행복입니다. 컨테이너를 다시 만들어도 예전에 쳤던 명령어가 남아 있거든요. 별것 아닌데, 개발하다 보면 이런 작은 편의가 은근히 큽니다. 매번 긴 명령어 다시 찾는 것도 피곤하잖아요.

Devcontainer를 설정할 때 제가 챙기는 체크리스트

새 프로젝트에 Devcontainer를 넣을 때 저는 아래 항목을 한 번씩 훑습니다. 거창한 기준은 아니고, 몇 번 데이고 나서 자연스럽게 생긴 제 나름의 습관이에요.

    • 런타임 버전이 명확한가?
      Python, Node.js, Java 같은 버전은 반드시 고정합니다. “최신 버전”은 생각보다 위험한 말이에요.
    • 컨테이너에 꼭 필요한 확장만 들어갔는가?
      확장은 적게 넣고, 필요하면 나중에 추가하는 편이 낫습니다.
    • postCreateCommand가 너무 무겁지 않은가?
      처음 생성할 때 모든 걸 다 하게 만들면 편하긴 한데, 너무 오래 걸리면 팀원이 싫어합니다.
    • 시스템 패키지는 Dockerfile에 명확히 남겼는가?
      누군가 로컬에서 따로 설치해야 하는 구조는 결국 다시 문제를 만듭니다.
    • 포트는 실제 사용하는 것만 열었는가?
      습관적으로 많이 열어두면 나중에 뭐가 어디서 뜨는지 헷갈립니다.
    • node_modules나 .venv가 로컬과 섞이지 않게 했는가?
      이건 정말 한 번 꼬이면 시간 잘 잡아먹습니다.
    • LLM이 참고하지 않아도 되는 파일은 정리했는가?
      오래된 실험 코드와 로그 파일은 AI에게도 사람에게도 별 도움이 안 됩니다.

저는 이런 체크리스트를 팀 위키에도 짧게 남겨뒀습니다. 길게 설명하지 않고, “우리는 이렇게 한다” 정도로요. 개발 문화라는 게 꼭 거창한 선언에서 만들어지는 건 아니더라고요. 이런 작은 약속들이 쌓이면 팀이 덜 흔들립니다.

Devcontainer가 모든 걸 해결하진 않지만, 개발자의 피로는 확실히 줄여줍니다

20년 넘게 개발을 하다 보니, 새로운 도구가 나올 때마다 조금은 조심스러워집니다. 한때 반짝했다가 사라지는 것도 많고, 도입 비용만 크고 실제 효과는 애매한 것도 많았거든요. 그래서 저도 Devcontainer를 처음부터 적극적으로 믿진 않았습니다. 그런데 실제 팀 프로젝트에서 써보고 나니 생각이 많이 바뀌었어요.

Devcontainer는 개발을 대신해주는 도구는 아닙니다. 하지만 개발을 시작하기 전의 불필요한 마찰을 많이 줄여줍니다. 특히 AI 바이브 코딩을 하는 요즘 환경에서는 더 그렇습니다. LLM에게 좋은 답을 얻으려면 프로젝트 맥락이 안정적이어야 하고, 개발환경도 재현 가능해야 합니다. Devcontainer는 그 기반을 꽤 깔끔하게 만들어줘요.

아직 Devcontainer를 안 써봤다면, 다음 팀 프로젝트나 조금 복잡한 사이드 프로젝트에서 한 번만 제대로 써보셔도 좋겠습니다. 처음 설정할 때는 살짝 귀찮을 수 있어요. 저도 그랬습니다. 그런데 한 번 만들어두면 그다음부터는 편합니다. 특히 여러 언어를 오가며 개발하는 분, 팀원마다 OS가 다른 환경에서 일하는 분, LLM 코딩 도구를 적극적으로 쓰는 분이라면 체감이 꽤 클 거예요.

제 기준에서는 이제 새 프로젝트를 열 때 .devcontainer 폴더부터 만들게 됐습니다. 예전에는 README부터 썼는데, 요즘은 실행되는 환경을 먼저 잡아요. 문서는 나중에 보완할 수 있지만, 환경이 흔들리면 코드도 사람도 같이 흔들리더라고요. 개발환경 세팅 때문에 매번 지치는 분이라면 Devcontainer, 한 번쯤 진지하게 써볼 만합니다. 아마 생각보다 금방 마음이 편해질 거예요.

댓글