컨테이너 가상화에 대한 이해를 하기 전에, 나는 Docker 기반으로 CICD 파이프라인 구축하기에 대한 학습을 했었다. 간단한 실습도 해보면서 docker가 무엇인지, 컨테이너가 무엇인지, 가상화는 무엇인지, 어떤 장점이 있었는지 등등에 대한 이해를 했었다. 하지만, 뭐든지 여러번 반복적으로 보지 않으면 암기가 되는건 아니기 때문에, 이해를 확실하게 했었는데 막상 "설명해보세요" 라고 하면 '그럴 듯 하게' 설명할 수는 없다. 그냥 아내가 "설명해줄래요?" 라고 하면 이해 시켜줄 수는 있지만 격식있는 자리에서 설명해야 하는 상황이라면, 진땀뺄 일이다.
어쨌든, 쿠버네티스까지 공부를 하기 위해서 도커부터 공부를 다시 시작하려고 한다.
나는 백엔드 개발자를 희망하고 있다. 그리고 클라우드 기술을 활용할 줄 아는 백엔드 개발자, 더 나아가서는 도커와 쿠버네티스까지 활용할 줄 아는 백엔드 개발자가 되기를 바란다. 우선은 그렇다. 그래서, 다시 한 번 더 확실하게 학습을 이어나가보도록 하겠다.
VM 가상화와 컨테이너 가상화 비교
VM 가상화는 독립적인 가상 머신(Virtual Machine)을 생성하여 각각 자체적인 운영체제(OS)와 커널을 가지고 실행됩니다. 이는 일반적으로 "부팅"이라는 과정을 통해 동작하며, 하드웨어를 가상화하여 자원을 분리합니다.
반면 컨테이너 가상화는 가상 머신과 달리 "부팅" 과정 없이 "런(run)"만으로 실행됩니다. 이는 호스트 운영체제의 커널을 공유하여 동작하기 때문입니다. 부팅 과정이 없다는 것은 운영체제 커널을 포함하지 않는다는 의미이며, 이를 통해 컨테이너는 더욱 가볍고 빠르게 실행됩니다.
컨테이너란 무엇인가?
컨테이너는 어플리케이션과 그 실행에 필요한 모든 환경(라이브러리, 설정 파일 등)을 하나로 패키징한 가상화된 경량의 격리된 프로세스입니다.
특징
- 경량화:
- 컨테이너는 최소한의 리소스를 사용하며, 예를 들어, Alpine Linux 기반 컨테이너는 크기가 약 5MB에 불과합니다. 이는 VM에서 일반적으로 사용하는 기가바이트 단위의 리소스와 비교할 때 큰 차이를 보여줍니다.
- 운영체제 수준의 가상화:
- 컨테이너는 호스트 운영체제의 커널을 공유하여 동작합니다. 커널을 포함하지 않으므로 더 빠르게 실행되며, 자원을 적게 사용합니다. 이를 통해 운영체제 수준의 독립성을 제공하면서도 다른 컨테이너와 격리된 환경을 유지합니다.
- 독립성 및 격리:
- 컨테이너는 다른 컨테이너와 독립적으로 실행되며, 상호 영향을 주지 않습니다. 기본적으로 "stateless(무상태성)" 환경으로, 상태값을 저장하지 않는 휘발성 환경에서 동작합니다.
- 격리된 환경은 방화벽 설정, 포트 제한 등을 통해 외부 접근을 통제할 수 있습니다.
컨테이너와 이미지의 관계
컨테이너 기술의 핵심은 이미지입니다. 이미지는 컨테이너의 실행 환경을 정의하는 설계도로, 어플리케이션과 해당 환경을 패키징한 것입니다.
- 도커 파일: 이미지를 정의하는 코드로, 이를 통해 컨테이너의 환경을 설정합니다. 도커 파일은 "Infrastructure as Code (IaC)"의 대표적인 예입니다.
- 이미지 빌드: 도커 파일에 따라 이미지가 생성되며, 이는 불변성을 가지고 동일한 환경을 어디서나 재현할 수 있습니다.
- 컨테이너: 이미지를 실행한 결과물로, 어플리케이션이 동작하는 논리적 공간입니다.
컨테이너 기술의 장점
- 효율성:
- 동일한 호스트에서 다수의 컨테이너를 실행할 수 있습니다.
- 한 줄의 명령어(docker run)로 빠르게 실행 가능하며, docker-compose를 사용하면 여러 컨테이너를 한 번에 관리할 수 있습니다.
- 이식성:
- 컨테이너는 도커 플랫폼이 설치된 모든 환경에서 동일하게 동작합니다. 이를 통해 온프레미스, 퍼블릭 클라우드, 개인 PC 등 다양한 환경에서 쉽게 배포할 수 있습니다.
- 일관성:
- 불변성을 가진 이미지를 사용하여 개발, 테스트, 운영 환경 간의 차이를 제거합니다. 이를 통해 배포 시 예기치 않은 오류를 줄일 수 있습니다.
- 비용 절감:
- 컨테이너는 리소스를 효율적으로 사용하며, 서버 관리에 필요한 비용을 절감할 수 있습니다.
- DevOps 친화성:
- 컨테이너는 개발팀과 운영팀 간 협업을 용이하게 합니다. 이를 통해 CI/CD(지속적 통합 및 배포) 환경을 효율적으로 구축할 수 있습니다.
컨테이너 개발 시 Best Practices
- 경량 이미지 사용:
- 베이스 이미지를 최소화하여 불필요한 리소스를 제거합니다. 예: Alpine Linux.
- 모듈화된 설계:
- 컨테이너는 MSA(마이크로서비스 아키텍처) 환경에 적합합니다. 마이크로 서비스를 구성할 때 가벼운 이미지를 사용해야 확장성을 유지할 수 있습니다.
- 자동화된 빌드와 테스트:
- 도커 파일과 도커 컴포즈를 활용하여 빌드, 테스트, 배포를 자동화합니다.
- 이미지 최적화:
- 불필요한 계층을 줄이고, 필요한 구성 요소만 포함하여 이미지를 경량화합니다.
컨테이너와 DevOps
컨테이너는 DevOps 모델에서 중요한 역할을 합니다.
- 개발팀과 운영팀의 협력: 컨테이너 기반 환경에서는 개발팀이 어플리케이션을 개발하고, 운영팀이 컨테이너 이미지를 관리하며, 두 팀 간 협력 관계를 강화합니다.
- CI/CD 구현: 컨테이너를 활용하면 어플리케이션 배포 및 업데이트를 자동화하여 효율적인 CI/CD 환경을 구축할 수 있습니다.
결론
컨테이너는 어플리케이션 중심의 경량 가상화 기술로, 현대 소프트웨어 개발 환경에서 필수적인 요소입니다.
특히, 개발 및 배포의 일관성을 유지하고, 비용을 절감하며, DevOps 워크플로우를 지원하는 데 최적화된 기술입니다.
컨테이너의 핵심은 "이미지 설계"와 "경량화"이며, 이를 통해 개발과 배포의 효율성을 극대화할 수 있습니다. 컨테이너 기술을 통해 여러분은 더욱 빠르고 안정적으로 어플리케이션을 배포하고 관리할 수 있습니다.
필기 내용의 확인 및 보완
1. 컨테이너가 "부팅하지 않는다"는 의미
- 컨테이너는 호스트 운영체제의 커널을 공유하여 동작하기 때문에 VM처럼 OS를 부팅하는 과정이 없습니다. 이로 인해 실행 속도가 매우 빠릅니다.
- 보완된 설명: 컨테이너가 커널을 공유한다는 점은 "경량화"와 직결되며, VM과 비교할 때 큰 장점 중 하나입니다.
2. 컨테이너와 이미지
- "이미지가 컨테이너 기술의 핵심이다"라는 설명은 맞습니다. 도커 이미지에는 어플리케이션 실행에 필요한 모든 요소가 포함되며, 이를 실행한 결과물이 컨테이너입니다.
- 보완된 설명: 도커 파일은 IaC(코드로 작성된 인프라)를 구현한 것이며, 이를 통해 이미지 생성 과정을 자동화할 수 있습니다.
3. 컨테이너는 운영체제 수준의 가상화 기술을 제공한다
- 맞는 설명입니다. 컨테이너는 VM과는 달리 호스트 OS의 커널을 공유하므로 "운영체제 수준의 가상화"라고 표현됩니다.
- 보완된 설명: 컨테이너 내부에는 커널이 포함되지 않지만, 리눅스 커널 네임스페이스(namespace)와 cgroups(컨트롤 그룹)을 통해 프로세스 간의 격리 및 자원 관리가 가능합니다.
4. 컨테이너의 독립성과 격리성
- "컨테이너는 격리된 프로세스이다"라는 설명도 맞습니다. 다른 컨테이너에 영향을 주지 않으며, 독립적인 실행 환경을 제공합니다.
- 보완된 설명: 컨테이너 간 통신은 기본적으로 격리되어 있지만, 네트워크 설정을 통해 필요에 따라 연결할 수 있습니다. 이 점은 DevOps와 마이크로서비스 아키텍처(MSA)에 매우 유용합니다.
5. Stateless 환경
- "컨테이너는 상태를 저장하지 않는 휘발성 환경"이라는 설명은 정확합니다. 컨테이너는 기본적으로 데이터를 휘발성으로 처리하며, 지속적 데이터를 관리하려면 외부 스토리지(예: 볼륨)를 사용해야 합니다.
6. 경량 컨테이너와 Alpine Linux
- Alpine Linux를 언급하며 "5MB 정도의 경량 컨테이너를 만들 수 있다"는 설명은 정확합니다.
- 보완된 설명: Alpine Linux는 보안성과 경량성을 위해 설계된 리눅스 배포판이며, 컨테이너 이미지 최적화에 자주 사용됩니다.
7. 컨테이너와 DevOps
- "컨테이너가 DevOps 모델에서 중요한 역할을 한다"는 설명은 정확합니다.
- 보완된 설명: 컨테이너는 CI/CD 파이프라인을 구현하는 데 필수적인 요소로, 빠른 배포와 테스트 환경의 일관성을 보장합니다.
틀리거나 오해의 소지가 있는 내용은 없었나?
크게 틀린 내용은 없었습니다. 다만, 일부 표현이 초보자에게는 모호할 수 있어, 이를 보완하기 위해 더 명확히 설명을 추가하거나 기술적 맥락을 조금 더 강조했습니다.
예를 들어:
- "커널이 없다": 컨테이너 자체에는 커널이 없지만, 실제로는 호스트 OS의 커널을 공유한다는 점을 더 명확히 했습니다.
- "포트를 열어주는 익스포즈(expose)": 컨테이너 내부 포트를 외부로 노출시키는 작업은 네트워크 설정과 관련이 있으며, 익스포즈 외에도 "-p 옵션" 등 다양한 도구가 사용됩니다.
1. 컨테이너 타입 (시스템 컨테이너, 애플리케이션 컨테이너, 라우터 컨테이너)
- 시스템 컨테이너: "OS 컨테이너"로 불리며, 전체 운영체제 환경을 격리하여 제공.
- 애플리케이션 컨테이너: 특정 애플리케이션을 독립적으로 실행.
- 라우터 컨테이너: 네트워크 라우팅 기능을 담당 (명시적으로 언급되는 경우는 드뭅니다).
검토: 일반적으로 도커는 애플리케이션 컨테이너에 초점을 맞춥니다. 시스템 컨테이너는 주로 LXC(Linux Containers)와 같은 기술에서 더 많이 사용됩니다. 라우터 컨테이너는 도커보다는 Kubernetes의 네트워킹에서 중요합니다.
2. PID 1번과 컨테이너의 주체
- 시스템 컨테이너에서는 OS 관련 프로세스가 PID 1번을 차지하며, 애플리케이션 컨테이너에서는 해당 애플리케이션이 PID 1번을 차지합니다.
- 검토: 맞는 설명입니다. PID 1번의 주체가 애플리케이션인지 OS인지에 따라 시스템 컨테이너와 애플리케이션 컨테이너가 구분됩니다.
3. 도커와 MSA
- 도커를 사용하여 3-tier 구조(프론트엔드, 백엔드, 데이터베이스)를 구성하고, API를 통해 서로 연결.
- 검토: 맞는 설명입니다. 도커는 마이크로서비스 아키텍처(MSA) 구현에 적합한 기술로, 계층별로 컨테이너를 분리하여 관리할 수 있습니다.
4. 이미지 공유 및 레지스트리
- 도커 허브, AWS ECR, 구글 GCR 등을 통해 이미지를 퍼블릭 또는 프라이빗하게 공유.
- 검토: 맞는 설명입니다. 도커 세이브 및 푸시, 풀 명령은 도커 이미지 공유 및 배포의 핵심 워크플로입니다.
컨테이너 기술 이해 - 컨테이너의 타입과 도커 워크플로
컨테이너의 타입: 시스템 컨테이너와 애플리케이션 컨테이너
컨테이너는 이미지 패키징 메커니즘으로, 애플리케이션과 해당 실행 환경을 하나로 묶어주는 역할을 합니다. 주로 아래 두 가지 컨테이너로 구분됩니다.
- 시스템 컨테이너 (OS 컨테이너):
- 운영체제 수준의 가상화를 제공합니다.
- PID 1번을 시스템 프로세스(Systemd)가 차지하며, 전체 운영체제를 격리합니다.
- 예: LXC(Linux Containers).
- 애플리케이션 컨테이너:
- 특정 애플리케이션을 독립적으로 실행하기 위한 경량 컨테이너입니다.
- PID 1번을 애플리케이션이 차지하며, nginx, Python, MySQL 등의 애플리케이션 실행에 사용됩니다.
- 주요 사례: 3-tier 모델(프론트엔드, 백엔드, 데이터베이스) 구성.
도커와 마이크로서비스 아키텍처(MSA)
도커는 MSA 구현에서 강력한 도구로 활용됩니다. 3-tier 구조(웹 티어, WAS 티어, DB 티어)를 각각 독립된 컨테이너로 분리하고, API를 통해 연결하여 서비스 메시를 구축할 수 있습니다. 이를 통해 애플리케이션의 확장성과 유지보수성을 크게 향상시킬 수 있습니다.
도커 이미지와 워크플로
도커에서 애플리케이션을 배포하기 위해서는 아래의 워크플로를 따릅니다.
- 도커 파일 작성:
- 애플리케이션 실행 환경을 정의합니다.
- 필요한 설정값, 라이브러리, 패키지 등을 코드로 작성.
- 이미지 빌드:
- 도커 파일을 기반으로 이미지를 생성합니다.
- 명령어: docker build -t [이미지명] .
- 이미지 테스트:
- 로컬 환경에서 생성된 이미지를 실행하여 컨테이너가 정상적으로 동작하는지 확인합니다.
- 명령어: docker run [이미지명]
- 이미지 푸시 및 저장:
- 이미지 공유를 위해 도커 허브, AWS ECR 등 레지스트리에 푸시합니다.
- 명령어: docker push [레지스트리/이미지명]
- 이미지 배포 및 실행:
- 저장된 이미지를 필요할 때 docker pull로 가져와 실행합니다.
- 명령어: docker pull [레지스트리/이미지명]
컨테이너를 통한 서비스 제공
도커를 통해 제공되는 서비스는 일반적인 서버 기반 서비스와 동일한 사용자 경험을 제공합니다. 그러나 도커는 경량화된 컨테이너 기술을 활용하여 효율성을 극대화합니다. 예를 들어, 3-tier 구조의 프론트엔드, 백엔드, 데이터베이스를 독립적으로 배포하고, 컨테이너 간 API 연결을 통해 사용자가 어플리케이션을 이용할 수 있게 합니다.
결론
컨테이너는 애플리케이션과 실행 환경을 패키징하여, 빠르고 일관된 배포를 가능하게 하는 기술입니다. 특히, 도커는 애플리케이션 컨테이너 실행에 최적화되어 있으며, MSA와 같은 현대적인 소프트웨어 아키텍처에 강력한 도구로 자리 잡고 있습니다. 이 글을 통해 컨테이너 기술과 도커의 기본 워크플로를 이해하고, 실무에 적용하는 데 도움이 되길 바랍니다.
Alpine Linux는 보안성, 경량화, 단순성을 목표로 설계된 리눅스 배포판입니다.
- 주요 특징:
- 경량성: 기본 설치 크기가 약 5MB 정도로, 일반적인 리눅스 배포판보다 훨씬 가볍습니다.
- 보안 중심: 기본적으로 보안 취약점이 적고, 패키지를 빌드할 때 Position Independent Executables(PIE) 등을 사용하여 보안을 강화합니다.
- 경량 컨테이너 최적화: Docker와 같은 컨테이너 환경에서 이미지 크기를 최소화하기 위해 자주 사용됩니다.
- 사용 사례:
- 경량화된 컨테이너 이미지를 만들기 위한 베이스 이미지.
- Nginx, Python 등 특정 애플리케이션의 컨테이너를 제작할 때 Alpine 기반 이미지를 활용.
질문 2: PID가 뭐고 PID 1번이란 게 무슨 말이야?
PID (Process ID)란?
- **PID(Process ID)**는 운영체제에서 실행 중인 프로세스를 식별하는 고유한 번호입니다.
- 운영체제가 프로세스를 실행할 때마다 새로운 PID를 할당하며, 이 번호를 통해 프로세스를 관리합니다.
PID 1번이란?
- PID 1번은 모든 프로세스의 "부모 프로세스"입니다.
- 리눅스/유닉스 시스템에서 PID 1번은 시스템 초기화 프로세스(Init 또는 systemd)가 차지하며, 이는 시스템 부팅 시 가장 먼저 실행되고 모든 다른 프로세스를 생성하는 역할을 합니다.
컨테이너와 PID 1번
- 시스템 컨테이너: 컨테이너 내부에서 PID 1번을 시스템 초기화 프로세스가 차지합니다. (예: systemd)
- 애플리케이션 컨테이너: 컨테이너 내부에서 PID 1번을 특정 애플리케이션 프로세스가 차지합니다. (예: Nginx, Python)
질문 3: systemd가 뭔데?
systemd란?
- systemd는 리눅스 운영체제의 시스템 및 서비스 관리 데몬입니다. 리눅스 시스템에서 PID 1번을 차지하며, 시스템 부팅부터 종료까지 프로세스와 서비스를 관리합니다.
주요 기능:
- 시스템 초기화: 부팅 시 필요한 서비스와 데몬을 실행.
- 서비스 관리: 서비스를 시작/중지/재시작 및 상태를 모니터링.
- 병렬화 지원: 부팅 속도를 향상시키기 위해 여러 작업을 병렬로 실행.
- 로그 관리: journald를 통해 시스템 및 애플리케이션 로그를 관리.
- 유닛 파일: 서비스, 타이머, 장치 등을 정의하는 설정 파일.
systemd와 init의 차이점:
- 전통적인 init 시스템은 순차적으로 프로세스를 실행하므로 부팅 속도가 느린 반면, systemd는 병렬 처리를 통해 빠르게 부팅합니다.
질문 4: WAS가 뭐야?
**WAS(Web Application Server)**란?
- WAS는 웹 애플리케이션 서버로, 동적인 웹 애플리케이션을 실행하고 클라이언트 요청(HTTP)을 처리하는 서버입니다.
- 클라이언트의 요청(예: 로그인, 데이터 저장)을 데이터베이스와 연계하여 처리하는 역할을 합니다.
- 단순한 정적 콘텐츠(HTML, CSS)만 제공하는 웹 서버와는 달리, 동적인 로직(Java, Python 등)을 실행합니다.
WAS의 주요 기능:
- 애플리케이션 로직 처리:
- 웹 서버는 정적 리소스(이미지, HTML)를 제공하지만, WAS는 사용자의 요청을 처리하고 동적인 결과를 반환합니다.
- DB 연동:
- 사용자의 입력 데이터를 데이터베이스와 연동하여 저장/조회/갱신 등의 작업을 수행.
- 트랜잭션 관리:
- 다수의 요청을 처리하면서 데이터 일관성을 유지.
3-tier 구조와 WAS:
- 3-tier 구조는 애플리케이션을 세 가지 계층으로 분리한 아키텍처입니다:
- 프론트엔드(Web Tier): 클라이언트와 직접 소통하는 레이어 (HTML, CSS, JavaScript).
- 백엔드(WAS Tier): 애플리케이션 로직을 실행하고 DB와 소통.
- 데이터베이스(DB Tier): 데이터를 저장하고 관리.
3-tier 구조와 컨트롤러-서비스-레포지토리의 관계:
- 컨트롤러: 웹 요청을 받아 적절한 서비스를 호출하는 계층 (Web Tier에 해당).
- 서비스(Service): 비즈니스 로직을 처리하는 계층 (WAS Tier에 해당).
- 레포지토리(Repository): 데이터베이스와 직접 상호작용하는 계층 (DB Tier에 해당).
Front-Back-DB도 3-tier 구조라고 할 수 있는가?
- 네, Front-Back-DB는 3-tier 구조를 간단히 표현한 것입니다.
- Front: 프론트엔드(Web Tier).
- Back: 백엔드(WAS Tier).
- DB: 데이터베이스(DB Tier).
결론
추가적으로 요약하자면:
- Alpine Linux는 경량 컨테이너를 위한 이상적인 리눅스 배포판.
- PID는 프로세스를 식별하는 번호이며, PID 1번은 시스템 초기화 프로세스를 의미.
- systemd는 리눅스의 현대적인 시스템 관리 도구로, 서비스 및 프로세스 관리를 담당.
- WAS는 동적 웹 애플리케이션을 처리하는 서버로, 3-tier 구조에서 백엔드 계층에 해당.
데몬(Daemon)이란?
**데몬(Daemon)**은 백그라운드에서 지속적으로 실행되며, 시스템이나 애플리케이션에 필요한 특정 서비스를 제공하는 백그라운드 프로세스를 의미합니다.
데몬의 주요 특징:
- 백그라운드 실행:
- 데몬은 사용자가 직접 인터랙션하지 않아도 시스템이나 다른 프로세스의 요청을 처리하기 위해 실행됩니다.
- 자동 시작:
- 대부분의 데몬은 시스템 부팅 시 자동으로 시작되며, 종료 시까지 실행 상태를 유지합니다.
- 특정 작업 담당:
- 네트워크 연결, 파일 시스템 관리, 로그 기록, 프린터 작업 처리 등 다양한 역할을 수행합니다.
데몬의 기원
- "데몬"이라는 용어는 그리스 신화의 **다이몬(Daemon)**에서 유래했으며, 이는 인간을 도우며 보이지 않는 존재를 의미합니다.
- UNIX 시스템에서 처음 사용되었으며, 현재 모든 운영체제에서 유사한 개념으로 활용됩니다.
데몬의 예시
- 시스템 데몬:
- systemd: 시스템 부팅, 서비스 관리 등을 담당하는 리눅스의 현대적인 시스템 관리 데몬.
- cron: 스케줄 작업(예: 자동 백업)을 실행하는 데몬.
- syslogd: 시스템 로그를 기록하는 데몬.
- 네트워크 데몬:
- httpd: Apache 웹 서버 데몬으로, HTTP 요청을 처리.
- sshd: SSH 연결을 관리하는 데몬으로, 원격 접속 서비스를 제공.
- ftpd: FTP 서비스를 제공하는 데몬.
- 데이터베이스 데몬:
- mysqld: MySQL 데이터베이스 서버를 실행하는 데몬.
- mongod: MongoDB 데이터베이스 서버를 실행하는 데몬.
데몬의 동작 원리
데몬은 일반적으로 아래 과정을 통해 실행됩니다:
- 프로세스 포크(Fork):
- 부모 프로세스가 자식 프로세스를 생성하여 백그라운드에서 실행.
- 세션 분리:
- 부모 프로세스와 독립된 세션에서 실행되며, 사용자 터미널과 연결이 끊어짐.
- 루트 디렉토리로 이동:
- 현재 작업 디렉토리와 독립적으로 동작하기 위해 루트 디렉토리(/)로 이동.
- 표준 입출력 분리:
- 표준 입력(stdin), 표준 출력(stdout), 표준 에러(stderr)를 파일로 리다이렉트하여 터미널과의 연결을 끊음.
데몬과 일반 프로세스의 차이점
특징 | 데몬 | 일반 프로세스 |
실행 위치 | 백그라운드에서 실행 | 포그라운드에서 실행 |
사용자와의 인터랙션 | 없음 (시스템이나 프로세스 요청 처리) | 사용자 입력을 받아 작업 수행 |
실행 주체 | 시스템에 의해 시작되며 독립적으로 실행 | 사용자에 의해 직접 실행 |
종료 시점 | 시스템 종료 시까지 지속 | 작업 완료 후 종료 |
데몬의 필요성
- 데몬은 시스템 관리와 서비스 제공을 자동화하여 사용자의 수동 개입을 줄이고, 운영체제와 애플리케이션의 효율성을 높이는 데 중요한 역할을 합니다.
- 예를 들어:
- 웹 서버 데몬(httpd)이 없으면 사용자는 매번 직접 요청을 처리해야 합니다.
- 데이터베이스 데몬(mysqld)이 없으면 데이터베이스 연결과 쿼리 처리를 매번 설정해야 합니다.
결론
데몬은 현대 컴퓨터 시스템에서 필수적인 백그라운드 서비스로, 시스템 안정성과 효율성을 유지하는 데 핵심적인 역할을 합니다. 데몬이 없다면 사용자와 시스템 간의 많은 작업이 비효율적으로 이루어질 수 있습니다.
우선 시작부터 VM 가상화와 컨테이너 가상화에 대해 비교를 해보자면 VM 가상화는 일반적으로 부팅을 하지만 컨테이너는 런을 합니다. 부팅을 하지 않는다는 얘기는 뭘 의미할까? 무언가가 없다는 이야기인데 그걸 이해하는 시간도 있을 것이다.
왜 컨테이너를 사용해야 하는가?
컨테이너가 무엇이냐?
컨테이너는 어플리케이션을 언제든 실행 가능하도록 만든 여러 가지 런타임을 가지고 있다. 그래서 컨테이너 기술 자체는 컨테이너가 우선이 아니고 그 컨테이너의 인프라를 만드는 이미지가 우선이다. 그래서 기본적으로 소스코드나 여러 가지 환경 요소, 종속관계 이런 모든 요소들을 하나로 묶어서 실행 환경으로 만들어주는 것을 이미지라고 부른다. 그런 이미지를 도커에서는 도커 파일, 도커 파일의 인프라를 제작을 하고 코딩을 하는 것이다. 그래서 도커 파일을 IaC, Infrastructure as Code라고 얘기를 한다. 그래서 도커 파일의 인프라의 요소들을 다 설정을 해놓고 그거를 빌드를 해주면 이미지가 되는 것이다. 그 이미지를 런을 하면 실제로 그 안에 있는 시스템 컨테이너 또는 어플리케이션 컨테이너 이런 것들을 실행할 수 있게 되는 것이다. 그걸 보통 우리가 런타임이라고 얘기를 한다. 그래서 컨테이너는 이미지와 함께 묶어서 패키징한, 내가 필요한 것들을 하나로 묶어놓은 논리적 공간이다. 이걸 우리가 컨테이너 기술이라고 얘기를 한다.
한마디로 어플리케이션과 종속 항목을 하나로 묶어서 실행하게 해주는 가상화된 경량의 격리된 프로세스.
경량 - 기존 VM과 얼마나 차이가 날까? 상당히 큰 차이를 보일 것이다. 그래서 어느 정도까지 경량을 가져갈 수 있느냐. 리눅스를 실제 서버에 깔든 VM에 깔든 그 용량이 기가바이트급이다. 그런데 최소한으로 잡았을 때 도커 컨테이너의 최소 용량의 리눅스는 무료 5메가바이트밖에 되지 않는다. 그걸 보통 우리는 알파인 리눅스라고 얘기를 한다. 그래서 그런 알파인 리눅스 배경으로 해서 어플리케이션 컨테이너를 개발을 하면 말 그대로 경량의 컨테이너를 만들 수 있다. 그래서 다른 말로 보통 마이크로 VM이다, 똑같은 가상 머신처럼 동작을 하기 때문에 VM이라는 말을 또 사용을 한다. 그래서 경량이라는 말은 그런 의미로 생각을 하면 된다.
그 다음에 운영체제 수준, OS 수준의 가상화를 제공한다. 이 문장만 들었을 때에는 VM하고 다를바가 없다. 일반 서버도 똑같이 운영체제 제공한다. 다만 이 운영체제에 컨테이너의 운영체제에는 커널이 없다. 커널이 없이 운영체제가 돌아갈까? 안 돌아간다 당연히. 그래서 도커는 플랫폼이다. OS 위에 올라가는 플랫폼 에저 서비스 중에 하나다. 그래서 OS에 있는 커널을 도커 컨테이너가 공유해서 쓰는 기술. 이걸 도커의 핵심이라고 생각하면 된다. 그래서 실제적으로 운영체제가 올라오긴 하지만, 그 안에 어플리케이션이 올라오긴 하지만 커널은 포함되지 않는다는 얘기이다. (나중에 다시 한 번 더 설명을 들을 수 있을 것.)
그래서 운영체제 수준의 어떤 가상화를 제공하는 거고, 한 마디로 독립된 OS인 것이다. 독립성을 갖고 있기 때문에 다른 컨테이너에, VM하고 똑같이 다른 컨테이너에 상호간에 연결을 하지 않기 때문에 영향을 주지 않는다는 얘기이다. 그래서 기본적으로 stateless, 실제적으로 상태값을 저장하지 않는 휘발성 환경이라고 생각하면 된다. 상태를 저장하지 않는 휘발성 환경. 그런데 여기서 말하는 격리형, 격리라는 말 자체가 실제적으로는 독립성을 갖는다는 말을 생각하면 좋을 것 같다. 격리된 프로세스, 독립된 프로세스. 격리라는 말은 하나의 운영체제가 독립적으로 운영할 수 있는 환경을 제공할 뿐더러, 운영체제에서 우리가 일반적으로 격리되었다고 하는 것은 뭐가 있을까? 운영체제가 격리되었다, 바로 방화벽이다. 기본적으로는 이 컨테이너 내부에 접근을 할 때 여러분들은 포트, IP 이런 건 기본적으로 생각할 수 있다. 그래서 기본적으로 우리가 포트를 열어주지 않으면 컨테이너에 포트를 통해서 트래픽을 전달하는 방법이 막혀 있다. 그래서 그런 부분을 어떻게 운영할 건지, 도커 커맨드이다. 도커 CLI를 통해서 그런 익스포즈하는, 포트를 열어주는 작업을 익스포즈라고 부른다. 당연히 그 내부에서는 또 그 포트가 열릴 수 있도록 어플리케이션이 그걸 잡고 있어야 되겠다.
자, 그 다음 세 번째 단어가 중요하다. 프로세스. 컨테이너는 사실은 프로세스이다. 아주 경량의 작은 OS를 담고 있는 프로세스이다. 우리가 알고 있는 리눅스 프로세스 조회할 때 우리 보통 ps 라는 명령어를 친다. 그 ps 명령어를 조회하듯이 컨테이너 또한 ps 를 통해서 조회가 가능한 프로세스 기술이라고 생각하면 된다. 자, 그래서 컨테이너는 패키징한 논리적 공간이다, 그 공간은 격리되어 있고, 한 마디로 그거는 프로세스로 동작을 하고 있다, 이게 컨테이너의 기본적인 모습이다.
자, 그 컨테이너는 여러분들이 원하시면 원하시는 공간에 도커를 설치하고 개인 노트북, 데스크탑 가리지 않는다. 기업 내의 온프레미스 서버라든가 AWS 같은 퍼블릭 클라우드, 이런 곳에서 언제든지 원하시는 도커 플랫폼을 이용해서 설치하고 빠르게 배포 가능한 환경을 제공한다. 거기다 플러스 알파로 저희가 클러스터 환경까지 구성을 하면 멀티 클러스터로 서버를 구축해놓고 마치 한 대의 서버처럼 동작하는 클러스터 환경으로 운영하게 되면 좀 더 확장성이 높게 평가가 되는 것이다.
그래서 컨테이너 기술을 통해서 우리가 할 수 있는 가장 이슈가 뭘까. 보통 우리 어플리케이션을 배포를 한다고 하면 서버가 필요하다. 서버 안에 OS도 깔아야한다. 당연히 네트워크 있어야 한다. 그 다음에 어떤 개발 도구를 쓸 것인지, 파이썬을 쓸거냐, 노드를 쓸거냐, 고를 쓸거냐, 자바를 쓸거냐, 그 관련된 환경도 구성을 해야 한다. 굉장히 반복적이고 불편한 작업이다. 시간 낭비, 인력 낭비, 이런 것들이 꽤 오래 걸릴 것이다. 더군다나 개발, 테스트, 운영 이 세 대의 서버를 만약에 운영을 한다면 똑같은 환경에서 이거를 셋업하기 위한 노력이 굉장히 힘들 것이다. 왜냐면, 쓰다 보면 처음 초기에는 우리가 서버 자체를 세 대, 개발, 테스트, 운영의 서버를 똑같이 개발을 할 수 있다. 하지만 쓰다 보면 실제적으로 바뀐다. 데이터도 바뀌고, 설정도 조금씩은 바뀔 수 있다는 것이다. 그런 부분에서 그런 서버들을 보통 스노우 레이크라고 하는 눈송이 서버라고 얘기를 한다. 그런데 도커 컨테이너는 실제로 이미지가 불변이라는 특징을 갖고 있기 때문에 항상 동일한 컨테이너로 배포가 된다. 그래서 그거를 개발용으로 쓰는 이미지든, 테스트든, 운영이든, 그 자체의 동일한 환경에서 쓰기 때문에 개발 환경에서 테스트를 거쳐서 운영까지 올 때 항상 같은 환경에서 서비스를 배포할 수 있다는 얘기이다. 그래서 결과적으로는 개발자 입장에서 봤을 때 가장 중요한 것이, 개발자는 어플리케이션 개발 그 자체에 집중할 수 있는 환경을 제공받을 수 있다는 얘기가 된다.
그럼 컨테이너는 앞서 설명한대로, 경량의 컨테이너라는 말을 많이 쓴다. 마이크로 VM, 경량의 컨테이너. 그 이유는 말씀드렸던 컨테이너는 모체가 아니다. 이미지가 모체다. 그래서 실제로 우리는 도커에 대해서 가장 중요하게 생각해야 하는 몇 가지 중에 하나가 바로 도커 파일인데, 그 도커 파일을 통해서 원하는 이미지를 개발해야 한다. 도커 파일은 인프라를 담고 있다는 말을 쓴다. 내가 원하는 OS 환경이 있다고 하면, 그 OS 환경에 필요한 것들을 집어넣는데, 그 OS 환경 등등을 넣을때 베이스 이미지라는 게 있다. 베이스 이미지는 도커 허브에서 기본적으로 제공을 한다. 그 중에서도 어떤 이미지를 선택하느냐가 굉장히 중요하다. 같은 엔진엑스, 파이썬 일지라도 실제적으로 이미지의 크기가 다르다. 크기가 다르다는 얘기는 내부에 세팅된 값이 다를 수 있다는 얘기이다. 그래서 우리가 실제적으로 컨테이너를 만들기 전에, 즉 이미지를 만들기 전에 어떤 환경, 어떤 OS가 필요하고 어떤 구성 요소가 들어가는지에 따라서 경량의 컨테이너냐, 좀 더 헤비한 컨테이너냐가 될 수가 있다. 그래서 뒤에 단에서는 우리가 이미지를 선택할 때, 베이스 이미지를 선택할 때 어떤 키워드를 기준으로 하면 좋지 않을까. 그래서 최소한의 이미지를 발생시키는 Best Practice에 해당이 되는 것. 그래서 나중에 Best Practice 란, 컨테이너 이미지를 개발할 때 가장 좋은 방법 중에 하나가 첫 번째 방법이 이미지를 가볍게 만드는 것이다. MSA 구축이 포인트인데 사실은, 컨테이너 서비스의 프로젝트는 요즘에 MSA로 구성이 되는 게 일반적인데, 마이크로한 서비스를 만들 때 헤비한 컨테이너가 들어가면 마이크로가 되지 않는다. 일 예로 말해보자면 그렇다는 것이다. 그래서 이제 경량의 컨테이너, 경량의 이미지로부터 출발한다는 얘기이다. 그리고 일반 서버에서는 어플리케이션 돌릴 때, 프로세스 하나하나 돌려가면서 우리가 환경 확인을 하고, 프로세스 돌아가는 거 확인하고 이제 돌아가는데, 도커에서는 도커런 (run 실행), 명령어 한 줄이면 끝난다. 그리고 한 번에 여러 개의 컨테이너도 돌릴 수 있는 도커 컴포즈, docker compose 라는, 아주 작은 도커에서 제공하는 아주 작은 오케스트레이션 도구를 또 제공을 할 수 있다. 그래서 도커 컴포즈를 통해서 멀티 컨테이너 서비스를 돌리는 게 또 하나의 목적이다. 우리가 뒷단까지 쭉 공부하다 보면 도커 컴포즈, 도커 파일, 이 두 가지를 만나게 되는데, 이 두 가지를 실제로 업무에 적용한다고 보면 된다. 우리가 도커 파일을 만들고, 도커 컴포즈로 컨테이너 테스트를 끝냈다고 치자, 이게 개인 환경이든, 또는 온프레미스 서버 환경이든, 클라우드 환경이든, 어떤 OS든 충분히 포터블할 수 있다는 얘기다. 이식성이 가능하다, 그러니까 내가 이미지를 만들었는데 그 이미지를 도커 허브에 올리거나 아니면 깃허브에 소스를 올리거나 프라이빗 레지스트리에 올리거나 AWS ECR에 올리거나, 그 이미지 자체가 구동하는 데는 도커 플랫폼만 깔려 있으면 제약이 없다. 그래서 이식성이 있다고 이야기를 하는 것이다.
컨테이너의 특징은 우선은 기본적으로 어플리케이션 환경을 집중적으로 관리할 수 있는데에 포인트가 있다. 한 마디로 이 컨테이너를 만들 때, 우리는 그 컨테이너 안에 있는 소스, 어떤 어플리케이션을 돌릴 것이냐, 그런 부분에 집중할 수 있다고 생각하면 되겠다. 컨테이너 자체는 어플리케이션을 중심으로 돌리는 것이다. 그 어플리케이션에 포인트를 주자. 그리고, 지속적인 서버 관리 비용을 들일 필요가 없는 것이다. 우리는, 플랫폼에 집중하면 된다. 플랫폼에 있는 리소스가 물론 서버베이스에서 돌아가니까 서버 관리도 어느 정도는 필요하겠지만, 서버베이스에서 돌아가는 어플리케이션 대비 컨테이너는 비용 절감을 할 수 있는 차원이 되게 많다는 것이다. 또 다른 특징으로, 컨테이너를 가지고 서비스를 개발하고 프로젝트를 운영을 하면 개발팀과 운영팀, 서로 대화를 자주 해야 하는 팀인데 대화가 쉽지 않은 그런 두 팀이 있다, 그 두 팀은 우선은 업무 분리가 되어있기 때문에 그런 것인데, 각자의 책임을 다하고 각자의 업무를 하기 때문에 그런 업무 분리로 인한 여러 가지 관리적 포인트에 좀 트러블이 있을 수 있다. 그런데 그런 부분들을, 이 개발팀과 운영팀을 컨테이너에서는 하나로 묶어서 개발팀과 운영팀의 협력관계 모델인 DevOps workflow를 구성하는데 컨테이너는 굉장히 합리적이다. 우선 개발팀에서 요구하는 부분들을 하나하나 반영을 해서 운영팀에서 이미지를 일반적으로 만든다. 물론 이거는 하나의 어떤 모델인 것이고 그렇지 않은 경우도 있을 거다. 개발팀에서 다 하는 경우도 있고, 아니면 운영팀에서 할 수도 있겠지만 일반적으로 근데 회사 규모에 따라서 개발팀에서 모든 걸 다 하는 경우도 있고 이렇게 분리된 환경도 있을 수 있다. 개발팀에서 요구하는 부분을 반영한 이미지를 개발하는 운영팀이 있고, 그 운영팀에서는 그 개발팀의 요구사항의 인프라, 한 마디로 이미지, 그 이미지를 제공을 한다. 개발팀에서는 거기다가 소스를 또 올릴 것이고, 또 다른 소스를 올려서 새로운 이미지 버전을 또 창출을 한다. 그럼 그거에 대해서 관리를 해주는 역할인 운영팀에서 그걸 지속적으로 관리하는 차원에서 지속적 통합과 배포를 원활하게 할 수 있는 환경을 만드는 데, 그걸 CICD라고 보틍은 얘기를 한다. 그래서 이거를 자동화 업무라고 하는데 이런 환경까지를 구축을 했을 때 상호간의 어떤 신뢰관계도 더 형성이 될 수 있는 가능성이 높고, 협력관계 모델이 가장 안정적으로 돌아갈 수 있다. 이게 만약 서버 베이스였다면, 그런 게 되게 힘들 것이다. 서버 자체의 하드웨어를 가지고 우리가 이렇게 만들기는 상당히 어렵다. 그래서 이제, 어떻게 보면 소프트웨어인, 도커. 도커도 소프트웨어인데, 소프트웨어를 이용한 컨테이너 개발 환경이다 보니까 그런 협력 모델이 쉽게 만들어질 수 있다는 이야기이다.
컨테이너는 주로 어떤 타입의 컨테이너가 있냐면, 우선 컨테이너는 패키징이다. 이미지를 패키징해서 그거를 런을 시켜서 사용할 수 있게 만들어주는 패키징 메커니즘이다. 그래서 이 컨테이너 패키징 메커니즘은 세 가지로 보통 얘기를 하는데, 시스템 컨테이너, 어플리케이션 컨테이너, 라우터 컨테이너. 사실 일반적인 것은 시스템하고 어플리케이션인데, 그냥 단순하게 보면 시스템 컨테이너는 OS 컨테이너라고도 부른다.
사실 도커의 핵심은 어플리케이션 컨테이너를 돌리는 게 도커의 주 역할이라고 생각해도 무방하다. 물론, 도커는 시스템 컨테이너, 어플리케이션 컨테이너 다 된다. 다 되는데, 도커를 쓰는 이유는 주로 어플리케이션이다. 시스템 컨테이너와 어플리케이션 컨테이너를 어떻게 구분을 할 것인가, 그건 바로 컨테이너 내부의 주인이다. 보통 시스템의 호스트의 PID, 프로세스 ID의 1번은 주로 시스템 D, 또는 옛날에는 이닛 프로세스라고 불렀다. 지금 조회해보면 대부분 다 시스템 D 프로세스가 나오는데 호스트의 PID 1번은 시스템 D이다. 그런데 가상화된 이 공간, 시스템 컨테이너의 1번, 여기에 PID 1번 또한 OS 주체가 1번이 된다. 그러니까 한 마디로 1번이 HostOS에도 있고 시스템 컨테이너에도 있는 것이다. 그런데 어플리케이션 컨테이너는 호스트를 떠나서 컨테이너에서 1번 PID를 갖는 주체가, nginx 컨테이너를 돌리게 되면 nginx 컨테이너 자체가 PID 1번을 가진다. 또는 Python 을 깐다, MySQL 을 깐다면, 이런 독립적인 어플리케이션 컨테이너를 깔면 그 내부에 들어가서 실제적으로 PID 1번을 줘야한다, PS로 말이다. 그러면 OS PID 가 아닌 해당 어플리케이션이 PID 1번을 잡고 있는 것이다. 그게 어플리케이션 컨테이너라고 보면 된다. 그래서 단일 어플리케이션을 돌린다, 그걸 위한 컨테이너를 만든다, 그게 도커가 하는 일이고 어플리케이션 컨테이너가 하는 업무이다. 그래서 그걸 위해서 서비스를 패키징하고 실행하도록 만들어진 컨테이너를 우리가 어플리케이션 컨테이너, 대표적으로 3-tier 모델의 Front-back-DB 의 컨테이너들을 이런 식으로, 프론트엔드에 뭘 쓰겠다, 백엔드에 뭘 쓰겠다, 각각의 독립된 컨테이너들을 하나의 도커의 런타임을 통해서 만들어주는 것이다.
도커가 처음 공개된 영상이 유튜브에 있는데, 기회가 되면 나중에 한 번 봐보자. (솔로몬 하익스라는 사람이 발표한 영상)
도커는 기본적으로, 여러 계층의 어플리케이션을 컨테이너로 분리하는 것이다. 여기서 말하는 계층은 티어, 3티어, 웹, 와스, 디비라고도 하는, 프론드를 웹티어, 백을 와스티어, 디비티어, 이런 계층을 컨테이너로 다 분리를 한다. 분리하고 간단하게 연결하는 기법, API 를 보통 사용하는데, API 연결 기법을 통해서 서비스 메시를 구축할 수 있다는 얘기이다. 그걸 보통 이제 우리가 MSA 라고 이야기를 한다. 도커가 이런 MSA 프로젝트에 유용하다는 이야기다.
서비스가 돌아가려면 당연히 인프라가 필요하다. 그 안에 런타임, 데몬도 들어가야 되고 환경도 들어가야 되고, 그런 환경으르 만드는 걸 우리는 이미지라고 얘기를 한다. 그래서 그 이미지를 만드는 게 도커 파일, 도커 파일을 통해서 이미지를 만든다. 그럼 내 로컬에 보유하기 보다는 프로젝트에 쓰기 때문에 또는 업무에 쓰기 때문에 개인적으로 돌려야 되기 때문에 아니면 옆에 있는 친구한테 고오유를 해줄 필요도 있고, 그 때 우리가 이제 퍼블릭이나 프라이빗하게 공유하는 방법들이 있다. 앞서 말씀드렸는데 도커 허브에 무료로 가입해서 퍼블릭하게 올리는 방법, 또는 도커 허브에서 프라이빗하게 제공해줄 수도 있다. 퍼블릭 클라우드 쪽도 마찬가지, AWS의 ECR, 구글의 GCR, 그런 R이 들어간 건 전부 다 레지스트리 라고 생각하면 된다. Github 에는 이미지가 다이렉트로 올라가는 건 아니지만, 그 이미지를 만드는 배경인 도커 파일과 소스, 또는 이미지를 백업할 때 쓰는 도커 세이브라는 명령이 있는데 이미지를 파일로 저장해서 공유하는 방법도 가능하겠다. 그게 Github의 역할이고 보통 이제 Github은 open share 방식이라고 한다. 도커 허브하고 깃허브는 연동이 되어서 깃허브에서 소스를 만약에 수정(modify) 하게 되면 그 즉시 도커 허브에 반영이 된다.(이건 유료 기능이다.)
자 이렇게 제공된 이미지들, 어떤 식으로 공유를 받았든 제공된 이미지를 기반으로 우리들의 서비스를 제공하고, 이걸 궁극의 목표는 사용자들이 사용할 수 있는 컨테이너로서 제공을 하는 것. 그럼 사용자는 그 주소를 이용해서 어플리케이션을 사용하는 그런 방식이다. 일반적인 서버랑 다를 바 없다. 똑같지만, 이거를 베이스 자체가 마이크로 VM 인 컨테이너로 돌린다는 이야기다.
도커 컨테이너는 보통 이런 과정을 거친다. 첫 번째로는, 인프라가 필요한데, 물론 베이스 이미지를 도커 허브에서 받아서 쓸 수 있지만, 그 이미지 안에는 우리가 원하는 인프라는 없어서, 우리가 원하는 인프라를 넣으려면 도커 파일에다가 원하는 세팅값, 라이브러리, 그 다음에 여러 가지 환경 설정, 패키지, 이런 것들을 등록하는 작업을 하는 것이다. 코드로 등록하는 것이다. 코드로, 그래서 그거를 빌드를 하면 이미지가 되는 것이다. 한 마디로, 패키징이 만들어지는 것이다. 어플리케이션 인프라를 구성한 도커 파일을 빌드를 하게 되면 어플리케이션 패키징이 만들어지는데 그 패키징을 통해서 도커 이미지가 만들어진다. 그걸 로컬에서 패키징 된 걸 어떻게 할까, 바로 런으로 컨테이너가 잘 돌아가는지 테스트를 한다. 잘 돌아가는 걸 확인하고 나면, 보통은 그것을 푸쉬를 한다. 퍼블릭 또는 프라이빗한 레지스트리, 또는 퍼블릭 클라우드에 있는 레지스트, 이런 곳에다가 저장을 시킨다. 업로드한다고 생각하면 된다. 공유를 위한 목적으로 push 를 할 수도 있고, 저장 자체가 목적으로 push 를 할 수도 있다. 어쨌든 push 해서 저장을 해놓으면, 언제든지 pull 을 통해서 내려받을 수 있다는 이야기다. 그래서 그 내려받은 이미지를 가지고 run 테스트를 통한 컨테이너 배포, 그게 결국에는 우리가 일반적으로 고객한테 제공하는 어플리케이션 서비스와 다를 바 없다는 이야기다.
'도커 & 쿠버네티스' 카테고리의 다른 글
도커 엔진 Docker Engine 의 상세 기술들 (0) | 2025.01.23 |
---|---|
어플리케이션 배포 방식 : 컨테이너 (Docker engine : dockerD, containerD, runC) (0) | 2025.01.21 |
어플리케이션 배포 방식 비교 : 일반서버 vs. 가상머신 vs. 컨테이너 (0) | 2025.01.20 |
Docker 컨테이너 가상화와 VM 가상화 비교 (1) | 2025.01.17 |