포스트

[도커-1] Docker 시작하기: 서버 설치부터 첫 번째 컨테이너 실행까지

[도커-1] Docker 시작하기: 서버 설치부터 첫 번째 컨테이너 실행까지
도커 아이콘

님 리눅스 좀 다룰 줄 알음? 혼자 서버 구축하고 배포할 수 있음? 도커는? 쿠버네티스는? db aws elk…..

처음 일을 시작할때는 개발자는 코드만 잘 작성하면 끝인 사람인 줄 알았다.
근데 연차가 쌓이고, 개발을 하면 할수록 내 범위가 넓어졌고 그것은 어느새 분명히 단순 코드의 영역을 넘어선 지 오래였다.
더욱이 요즘처럼 AI가 코드를 작성해주고, 사람이 그걸 검수하고 수정하는 시대에는
신기술을 캐치하고 인프라를 구축하는 영역이 더 중요해졌다고 생각한다.

사실 도커라는 개념이 나온지는 이미 10년도 넘었고, 쿠버네티스라는 도커를 이용하여 만든 서비스도 상용화된지 한참 지났다.
근데 이제서야 시작해보는 이유는 단순하다. 내가 일했던 환경에서는 도커를 사용하지 않았기 때문이다.
하지만 이미 업계에서는 주류가 되었고 이 개념을 싹 갈아치우는 신기술이 나오지 않는 이상
계속해서 쓸 것이라고 예상되기 때문에 미리 준비해두고자 한다.


도커의 핵심 개념


도커 흐름

세줄 요약은 다음과 같다.

  1. 도커 이미지를 만든다.
  2. 이미지를 실행시킨 도커 컨테이너를 만든다.
  3. 도커 서버에서 컨테이너를 돌린다.


이미지는 뭐고 컨테이너는 뭔데?

도커 이미지란 서비스 하나의 스냅샷이라고 생각하면 된다.
MySQL을 예로 들어보자. 서비스를 만들때 꼭 필요한 초기 상태가 있을것이다.
버전, 접속 계정 정보, 서버 포트 번호, HA 설정, DB의 설정값, 테이블 스키마, 기본 데이터 등..
이렇게 모든 설정이 끝나, 배포만 하면 되는 상태를 도커에서는 ‘이미지’ 라고 한다.
도커 컨테이너란 이미지 파일을 프로세스화 시켜 만든 하나의 인스턴스 서버라고 생각하면 된다.
이렇게 도커가 지향하는 방향인 1컨테이너 = 1이미지를 플랫폼에 맞게 개별로 쪼개서 전부 컨테이너에 올리면 도커 서버가 완성된것이다.

이게 기존 서버 구성과 뭐가 다른거임? 원래도 AP서버, DB서버 등등 분리해서 구성하잖아

기존 서버의 구성 방식과 도커식 구성 방식은 겉으로 봤을때는 거의 동일해보인다.
하지만 격리성, 이식성 면에서는 상당히 큰 차이가 있다.
기존 서버에서 프로세스를 나누는 것과 도커 컨테이너를 나누는 것의 가장 큰 차이점은 운영체제(OS) 수준의 격리여부와 애플리케이션 환경을 포함하는지 여부이다.

격리성

특징도커 컨테이너 방식기존 서버/프로세스 방식
격리 수준OS 커널 수준 (namespace, cgroups 사용)
높은 격리성
프로세스 수준 (OS가 제공하는 사용자/그룹 권한 제어)
상대적으로 낮은 격리성
파일 시스템컨테이너별로 독립된 파일 시스템을 가짐모든 프로세스가 호스트 서버의 공통 파일 시스템을 공유
자원 관리cgroups를 통해 CPU, RAM을 컨테이너별로 정확히 제한 및 할당 가능프로세스 우선순위 설정만 가능하며, 특정 프로세스가 자원을 독점하기 쉬움
  • 기존 방식은 A프로세스 때문에 B프로세스도 문제가 생기고 이로 인해 해당 서버 전체에 문제가 생기는 상황이 발생하지만
    도커 환경에서는 컨테이너별 격리가 되어있으므로 발생하지 않음

이식성

특징도커 컨테이너 방식기존 서버/프로세스 방식
포함되는 것애플리케이션 코드 + 런타임 환경 + 모든 의존성애플리케이션 코드 (런타임은 서버에 이미 설치)
이식성이미지만 있으면 OS나 환경에 관계없이 어디서든 동일하게 실행됨
이식성 매우 높음
서버 환경(OS 버전, 라이브러리 경로 등)에 종속적
환경이 다르면 오류 발생 가능성이 높음
이식성 낮음
문제 발생“내 컴퓨터에서는 되는데…” 문제가 없어짐 (환경이 이미지에 고정)서버 환경 설정을 다시 해야 하거나 의존성 불일치 문제 발생 가능
  • 기존 방식의 “자바 21을 설치하고, 톰캣을 설치한 후, war 파일을 배포하세요” 는 복잡하고 버전 등 환경에 영향을 많이 받는데에 비하여
    도커는 자바 21과 톰캣 설치, war파일이 포함된 이미지를 실행하면 끝이므로 어느 서버던간에 이식이 쉽게 가능함

결론: 한 번 만들어 놓으면 언제, 어디서든 쉽고 빠르게 격리된 환경의 안정적인 서버를 구축할 수 있다.


도커 서버 설치 과정


도커는 기본적으로 리눅스를 기반으로 하는 엔진이기 때문에 리눅스 환경이 필요했다.
도커에서 제공하는 Docker Desktop 이라는 윈도우 환경에서도 도커를 쓸 수 있게 만드는 도구가 있었지만,
최대한 실무에서의 환경과 동일하게 맞추기 위하여 해당 방법은 사용하지 않고 정석적인 리눅스에 설치하는 방식으로 하려고 한다.
다만 내 PC자체를 리눅스로 바꿀수는 없었기에 VM을 이용하기로 했다.
VMware를 설치하고 OS를 Rocky Linux로 부팅한 뒤 실행한 화면이다.

터미널 첫 화면

도커가 설치되어있지 않기 때문에 당연히 명령어가 정상적으로 실행되지 않는다.

최대한 환경에 영향을 받지 않기 위하여 정석적인 방법인 dnf를 이용하여 수동 설치하는 방식으로 진행하였다.
다음은 도커 서버 설치 과정 영상이다.

여기까지 완료되면 도커 서버의 설치는 완료된 것이라고 볼 수 있다.

각 구문별 해석

  • docker version
    • 현재 설치되어있는 도커의 버전을 확인하는 명령어. 클라이언트/서버가 나누어져 출력된다.
  • sudo dnf config-manager --add-repo <https://download.docker.com/linux/centos/docker-ce.repo
    • Rocky Linux와 호환되는 도커의 CentOS/RHEL 도커 공식 저장소를 추가한다.
  • sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    • 도커를 구성하는 데 필요한 모든 핵심 소프트웨어 패키지들을 시스템에 최신 버전으로 설치한다.
  • systemctl status docker
    • 도커 서비스의 현재 상태를 확인한다.
    • dead, failed: 서비스 중지, running: 서비스 기동중
  • systemctl start docker
    • 도커 서비스 기동시킨다.
  • (선택) sudo usermod -aG docker $USER
    • 현재 사용자에게 도커 소켓에 접근할 권한 그룹을 추가한다.


도커 이미지


앞서 도커 이미지는 일종의 스냅샷 이라고 설명했었다.
그렇다면 이미지는 어떤 방식으로 만들어질까?
Dockerfile을 실행해서 만들어진 결과물을 도커 이미지라고 한다.
여기서 도커 파일이란 사용자가 명령어를 모아 만든 텍스트 기반의 파일을 일컫는다.

  • 사용자가 직접 입력한 명령어를 모아둔 텍스트 파일 -> 도커 파일
  • 도커 파일을 docker build 명령으로 실행/빌드한 파일 -> 도커 이미지

다음은 도커 파일의 예시이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
# 베이스 이미지 지정
FROM node:18-alpine
# 작업 디렉토리 설정
WORKDIR /app
# 패키지 파일 복사 및 의존성 설치
COPY package.json .
RUN npm install
# 소스 코드 복사
COPY . .
# 노출할 포트 지정
EXPOSE 3000
# 컨테이너 실행 명령어
CMD ["npm", "start"]

명령어를 이해할 필요는 없다. 흐름만 보자.

이런 형식의 명령어로 이루어진 도커 파일을 작성하고
docker build를 통하여 실행/빌드를 하면 도커 이미지가 만들어진다.

이미지 레이어

도커 파일을 작성하다보면 의문점이 생긴다.

변경 내역이 발생할 때 마다 이미지 전체를 다시 다운로드 받아야 하는건가?

그렇다면 상당히 비효율적일 것이다.
수정된 1%를 위해 99%의 작업을 처음부터 다시 시작하게 된다면 말이다.
도커는 이 부분을 고려하여 설계되었다.
도커 파일이 docker build 명령을 통해 빌드될 때, 파일 시스템을 변경하는 각 명령어는
독립적인 작업 단위(레이어)를 생성하고, 이 레이어는 이후 재활용을 위해 도커의 로컬 캐시에 저장된다.
도커 파일에 수정이 발생하면 변경이 되지 않은 구문이 만든 레이어는 캐시에서 가져와 그대로 재사용하고,
변경이 발생한 레이어만 생성하여 기존 레이어 스택의 최상단에 추가하여 새로운 이미지를 완성시킨다.
그리고 이미지 다운로드시 마찬가지로 변경이 발생한 레이어만 다운로드하고 나머지는 재활용하여 처리한다.

#명령어파일 시스템 변경?레이어 생성 여부생성 레이어 종류
1FROM node:18-alpineYes생성베이스 이미지 레이어 (N개)
2WORKDIR /appNo미생성메타데이터 (작업 디렉토리 설정)
3COPY package.json .Yes생성파일 시스템 레이어 (패키지 파일 추가)
4RUN npm installYes생성파일 시스템 레이어 (의존성 설치 결과)
5COPY . .Yes생성파일 시스템 레이어 (소스 코드 추가)
6RUN npm run buildYes생성파일 시스템 레이어 (빌드 결과)
7EXPOSE 3000No미생성메타데이터 (포트 선언)
8CMD ["npm", "start"]No미생성메타데이터 (실행 명령어)

기존 도커파일에 6번 라인의 명령어를 새로 추가했다면?

  • 최종 이미지 레이어 개수: (베이스 이미지 레이어 + 생성된 3개의 레이어) + 새로 추가한 1개의 레이어

이미지 레이어

시각화한 이미지 레이어 구조


도커 파일 작성부터 빌드, 이미지 생성, 컨테이너 띄우기까지


간단한 HTML 파일을 nginx 컨테이너를 이용해 띄워보자.

마지막에 localhost:8080으로 접속하여 성공적으로 웹서버 컨테이너가 띄워진 걸 확인할 수 있다.

각 구문별 해석

  • mkdir docker-web-server, cd docker-web-server
    • 웹서버 도커파일을 만들기 위한 디렉토리를 생성한다.
  • echo "Hello Docker World! This is a Web Server. I'm nayatrei." > index.html
    • 텍스트를 출력하는 index.html 파일을 만든다.
  • touch Dockerfile, vim Dockerfile
    • 도커파일을 만들고, 편집기로 들어간다.
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    
      # 1. 가벼운 Alpine 기반 Nginx 이미지를 베이스로 사용
      FROM nginx:alpine
      # 2. 현재 디렉토리의 모든 파일(index.html 포함)을 Nginx의 기본 웹 루트로 복사
      # Nginx Alpine의 기본 웹 루트는 /usr/share/nginx/html 이다.
      COPY . /usr/share/nginx/html
      # 3. Nginx는 기본적으로 80번 포트를 EXPOSE 한다. (생략 가능)
      EXPOSE 80
      # 4. 컨테이너가 시작될 때 Nginx를 포그라운드(Foreground) 모드로 실행한다. (생략 가능)
      CMD ["nginx", "-g", "daemon off;"]
    
  • docker build -t docker-web-server:1.0 .
    • -t docker-web-server: 이미지에 docker-web-server라는 이름과 1.0이라는 태그를 지정한다.
    • .: 현재 디렉토리에 Dockerfile이 있음을 알린다.
  • docker images
    • 로컬 저장소의 도커 이미지 리스트를 출력한다.
  • docker run -d -p 8080:80 --name docker-web-server docker-web-server:1.0
    • -d: 컨테이너를 백그라운드에서 실행한다.
    • -p 8080:80: 호스트 PC의 8080 포트를 컨테이너의 80 포트로 연결한다.
    • –name docker-web-server: 컨테이너 이름을 지정한다.
  • docker ps
    • 현재 Up(실행 중) 상태인 컨테이너들의 목록을 보여준다.


다음 목표

이로써 서버 설치의 첫걸음부터 시작해, 도커파일을 작성하고, 이를 빌드하여 이미지를 생성하고,
컨테이너를 실행해 웹서버 동작을 확인하는 도커의 핵심 워크플로우를 경험해보았다.

다음 장에서는 컨테이너를 여러 개 띄워 상호작용하게 만드는, 다중 컨테이너 환경을 구축해 볼 예정이다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.