[16주차 Day4] [네 번째 스프린트] 웹 개발 파이프라인 구축

반 히·2024년 6월 19일

데브코스

목록 보기
48/58
post-thumbnail

📚 Part 0 Intro


📁 웹 개발 파이프라인 구축

📌 학습 목표

  • "풀 사이클 (full cycle) 개발"이라는 것이 무엇을 뜻하는 것일까?
  • (웹 서비스 개발의 관점에서) 과목 제목에 포함된 "파이프라인 (pipeline)"이 무엇을 뜻하는 것일까?
  • CI/CD란 무엇이고 이것은 왜 필요한 것일까?
  • 여기에 이용되는 도구들이 여러가지 있던데, 각각의 역할이 무엇이고 어떻게 활용하는 것일까?
    • Docker (도커)
    • Kubernetes (쿠버네티스)
    • Jenkins(젠킨스)
    • 등등

📌 웹 개발 파이프라인

코드 개발

지속적 통합 (CI; Continuous Integration)

  • 빌드 (코드 빌드)
  • 테스트
    • 빌드된 코드에 대해서 테스트
    • 원하는 대로 잘 동작하고 있는지, 성능 요구 조건을 만족하는지 등등을 테스트
  • 코드 병합
    • merge, integration
    • 서로 다른 개발자들이 만든 코드의 경우, 잘 병합하여 지속적 통합

코드의 개발 또는 개선, 코드의 진화가 이루어짐에 따라서 지속적으로 이루어짐 (자동으로)

지속적 인도 (CD; Continuous Delivery)

코드 리포지토리에 자동으로 릴리스

지속적 배포 (CD; Continuous Deployment)

프로덕션 환경에 자동으로 배포

이러한 절차들을 자동화하여 실수의 여지를 줄이고, 효율을 어떻게 높이는가



📁 배포/인도 자동화의 중요성

📌 전통적 인도 프로세스

Product Owner (Customer)

맨 처음 소프트웨어의 요구 조건의 궁극적인 끝은 사용자에게서 오는 것이다. 비즈니스 입장에서는 소프트웨어 개발을 의뢰한 customer의 요구 조건으로부터 발생한다. (물론 기술적인 요구 사항이 아닐 수도 있다) 이 요구 조건을 기술적인 요구 사항으로 해석하고, 개발팀에 개발에 필요한 요구 사항으로 전달한다.

Development (개발팀)

  • Analysis
    • 요구 사항을 분석한다
  • Planning
  • Implementation
    • 코드 구현
  • Unit Testing
    • 내가 쓴 코드가 나에게 주어진 요구 사항을 만족하는지 검사한다
  • Demo

Quality Assurance (QA)

  • Integration Testing
    • 서로 다른 개발자 또는 서로 다른 개발팀에서 만든 코드가 잘 통합되는지
  • Acceptance Testing
    • 고객의 요구 조건을 잘 만족시키는지
  • Non-functional analysis
    • 비기능적 요구 사항
    • 검사하여 소프트웨어의 품질을 보증한다.

Operations

  • Release : 코드 릴리즈
  • Monitoring : 내 시스템이 잘 동작하고 있는지 모니터링

📌 전통적 인도 프로세스의 한계점

  • 느린 인도 기간
    • 여러 조직이 얽혀있고, 그 단계들을 거쳐가는 게 쉽지 않음
    • 개발 요구 사항이 정의된 때로부터 제품 전달이 완료되기까지 긴 시간 소요
  • 느린 피드백 주기
    • 개발팀의 효율성 향상에 걸림돌로 작용
  • 자동화 미비
    • 요구사항으로부터 실제 소프트웨어가 릴리스되기 까지의 시간이 기므로 릴리스 횟수 적음
    • 릴리스 회수가 적으므로 자동화 필요 감소 → 릴리스 기간 예측 어려워짐
  • 핫픽스 위험성
    • 충분히 테스트하지못하고 코드가 릴리스 될 수 있음
      ⇒ 자동화가 굉장히 중요하다.
  • 개발 문화 건전성 제한
    • 팀 스트레스, 의사소통 부족, 책임의 분산, 낮은 업무 만족도, ...

📌 해결책: 지속적 인도/배포 방식

  • 변경 내용이 단지 코드 한 줄이라고 할 때,
    • 이를 배포하는 데 어느 정도 시간이 소요되는가?
    • 이 배포 작업을 반복해서 안정적으로 수행할 수 있는가?
  • 해결안 : 프로세스의 각 단계를 자동화
    • 빠른 제품 인도
    • 짧은 피드백 주기
    • 위험도가 낮은 릴리즈 : 반복과 롤백
    • 유연한 릴리즈 정책 결정 가능

      Git을 활용한 SCM에서 논리적 연관성이 있는 변경사항을 묶어 잘게 자주 커밋하는 것과 유사. 자동으로 빌드하고 통합되고 인도될 수 있게 하는 것이 Ci/CD의 주요 원칙이다.

📌 자동 배포 파이프라인

코드의 통합, 테스트, 배포는 (전통적 인도 방식에서와 마찬가지로) 매우 중요한 단계들이다. 각 단계를 유지하면서 동시에 자동화하는 것이 필요하다. 또한 지속적인 모니터링도 필수 이다.

코드 변경 → 지속적 통합 (CI) → 자동 인수 테스트 → 구성 관리

  • 지속적 통합 : (서로 다른 개발자에 의한) 코드가 문제 없이 통합되는지 확인한다.
  • 자동 인수 테스트 : 구현한 기능이 고객 요구사항과 맞는지 확인한다
  • 구성 관리 : 환경 구성, 소프트웨어 배포 (수동 운영 단계를 대체)

📌 지속적 통합 (CI; Continuous Integration)

✔️ 코드가 올바르게 빌드 및 통합되는지를 자동으로 확인하는 과정

  • 리포지토리에서 코드를 체크아웃 (예전에는 CVS, SVM을 사용했고 요즘은 git을 많이 사용함)
  • 빌드 (컴파일 및 링크 등)를 수행하고 단위테스트(UT; Unit Test)를 행함
    • 테스트 커버리지(test coverage) 리포트 생성
  • 코드 품질을 검증
    • 정적 분석(static analysis)을 통한 규칙 검사
    • 코딩 규약 등의 준수 여부 검사
      ✔️ 개발팀에 1차적인 피드백 제공

📌 자동 인수 테스트

✔️ 인수 테스트 (UATl User Acceptance Test)

  • 제품이 릴리즈할 준비가 되었는지를 "사용자(고객) 요구사항에 견주어" 확인
  • 전통적으로 QA (Quality Assurance) 팀의 역할
    • cf) unit test(단위 테스트; UT)는 개발 팀의 역할
  • 통합 테스트, 인수 테스트, 비기능적 분석 (성능, 확장성, 보안, ...) 등을 포함

✔️ CD 파이프라인에 통합

  • 품질 점검을 나중에 하는 것이 아니라 개발 중에 제품에 내재시키는 것
  • 개발자가 구현을 마치는 즉시 고객이 원하는 제품인지를 검증
  • 소프트웨어의 인도 결정을 자동화한다는 뜻

📌 구성 관리

🔗 구성 관리 (Configuration Management)

  • 소프트웨어와 환경 변화를 추적하고 제어
  • 전통적으로 운영 (Operation) 팀의 역할
  • 필수 도구 준비와 설치
  • 응용의 배포와 관련한 다양한 서비스 인스턴스와 배포 버전 관리

🔗 CD 파이프라인에 통합

  • 프로덕션 환경의 응용을 자동으로 구성하고 배포
    • 자동화 할 수 있어야 잦은 릴리스에 대해서 안정적이게 됨
  • 구성 관리 도구를 이용하여 구성 관리 파일을 버전 관리 시스템에 저장하고 변경 이력 추적

📌 CD를 위한 기술적 전제조건

  • 자동 빌드, 테스트, 패키징, 배포
    • 전체 프로세스 중 자동화되지 않는 부분이 있다면 지속적 인도가 불가능
  • 신속한 파이프라인 실행
    • 리포지토리에 커밋 발생할 때마다 실행되어야 하므로 소요시간이 길면 안 됨
  • 신속한 장애 복구
    • 신속한 롤백이 가능해야 하며, 그렇지 못할 경우 잦은 릴리스에 따른 위험도가 높아짐
  • 무중단 배포
    • 잦은 (하루에도 수 회) 배포가 이루어지므로 배포 중 서비스 다운타임(downtime)이 발생하면 안 됨
  • 트렁크 기반 개발
    • 로컬 브랜치에만 코드 체크인하면 코드 통합 검증이 이루어지지 않고 릴리스 회수가 줄어듦


📁 웹 개발 파이프라인 구성 도구

📌 몇 가지 의문점들

❓ 이렇게 많은 도구들의 사용을 익혀야 하나?

✅ Yes - 도구와 환경을 올바르게 설정하는 것이 파이프라인 구축에 있어서 중요함

❓ 그렇다면, 파이프라인 구축에서 가장 중요한 것은 도구 사용법을 익히는 것일까?

❌ No - 더욱 중요한 것은 각 도구가 프로세스에서 담당하는 역할과 요구되는 조건을 이해하는 것이다.

❓ 여기서 소개되는 도구들이 필수인 것인가?

❌ No - 같은 역할을 하는 다른 도구들이 많이 존재한다. 따라서 환경에 맞는 도구를 유연하게 선택해야 한다.

❓ 그렇다면, 새 도구를 선택할 때마다 다 새로 익혀야 하는 것인가?

❌ No - 역할과 요구조건이 같은 도구들은 세부 사항에 차이가 있다고 하더라도 대부분 유사하기 때문이다.

📌 파이프라인 자동화 도구들

  • 컨테이너 가상화 및 클러스터 운용
    • Docker + Kubernetes
  • 소프트웨어 개발 파이프라인 자동화 서버
    • Jenkins
  • 구성 관리 자동화
    • Ansible
  • 소프트웨어 버전 관리 (SCM; Source Code Management)
    • Github
  • 그 외
    • 빌드 도구(자동화 지원), 단위 테스트 프레임워크, 정적 코드 분석기, 인수 테스트 프레임워크, ...

📌 컨테이너화 (Containerization)

응용 프로그램, 설정(configuration) 파일, 라이브러리, 그리고 이들 사이의 의존성 관계를 한 군데에 묶어 (컨테이너 안에 넣어) 관리한다.

  • 소프트웨어 개발 및 배포의 효율과 안정성을 향상시킨다
  • 하이퍼바이저(hypervisor)에 의한 가상 기계 (VM; virtual machine)의 대체 및 보완 방식으로 각광받고 있다.
  • 시스템 의존성이 최소화되어 소프트웨어 시스템의 이식이 용이해진다
  • 예측 가능하고 유연한 소프트웨어 실행 환경을 제공하여 클라우드 컴퓨팅 인프라에서 활용도가 높다.

📌 지속적 통합 파이프라인 (CI Pipeline)

리포지토리에 코드 커밋이 발생할 때마다 빌드, 단위 테스트, 정적 분석 등을 행한다.
이때 CI 서버로는 Jenkins가 활용된다. Jenkins Slaves에 빌드, 테스트, 정적 분석 등을 맡겨서 수행한다. 수평적으로 확장이 가능하다.

📌 자동 인수 테스트

Docker와 Jenkins를 결합하여 인수 테스트 환경을 만들고 테스트를 수행한다. 개발한 시스템이 사용자의 요구 사항으로부터 잘 만족시키고 있는가를 검증하는 것이 Docker와 무슨 상관이 있을까? Docker 이미지를 만들어놓고 응용 소프트웨어를 컨테이너화해서 Docker host 안에 실제로 실행을 해보는 것이다. 실제로 운영될 환경과 유사한 모습으로 만들어서 테스트할 수 있게 한다.

즉, 흐름은 코드 개발자가 코드 리포지토리 (github)에 코드를 push하면 이것을 pull 또는 clone을 통해 Jenkins에서 Jenkins Slaves를 통해 단위 테스트나 정적 분석 등을 행한다. 그 후, 통합이 잘 되었으면 이미지 레지스트리에 Docker image(Container image)를 만들어서 올린다. 이 이미지를 가져다가 실제로 Docker가 돌 수 있는 host에서 응용 소프트웨어를 컨테이너로 실행을 하여 UAT를 행하는 방법이다.

📌 쿠버네티스 클러스터링

  • 클러스터 : 컴퓨팅이 가능한 노드(물리적인 컴퓨터들 혹은 가상화된 컴퓨터)
  • 쿠버네티스 : 클러스터 위에서 컨테이너들을 실행해주는데 도움을 주는 컨테이너 오케스트레이션 툴

Docker Host 대신에 Kubernetes Cluster가 연결된 형태이다. 쿠버네티스 클러스터의 형태로 컨테이너를 실행한다.

📌 구성 관리 (Configuration Management)

Staging Cluster와 Production Cluster가 있다. 즉, 환경을 다중으로 생성을 하고 미러링한다는 것이다. 이를 통해 테스트 환경과 프로덕션 환경을 미러링한다. Staging Cluster에서는 실제로 잘 실행이 될 수 있을지 테스트를 하는데 이용을 한다. 똑같은 환경이므로 Production Cluster에서도 잘 돌 것이라고 생각하며 이를 배포한다.



📚 Part 1 도커를 통한 컨테이너 가상화


📁 컨테이너 가상화와 도커

📌 가상화 (Virtualization)

  • 컴퓨팅 자원(리소스; resource)의 추상화를 일컫는 광범위한 용어
  • (딱딱하게) 물리적인 컴퓨팅 자원의 특징을 다른 시스템, 응용 프로그램, 최종 사용자들이 자원과 상호 작용하는 방식으로부터 감추는 기술
  • (부드럽게) 컴퓨터 안에 또 다른, 즉 가상의 컴퓨터가 존재하도록 하는 기술

📌 가상화 컴퓨팅의 이점

🔗 시스템 측면

  • 시스템 이용률 (utilization)의 향상
  • 설정(configuration)의 구성과 복원이 용이

🔗 비즈니스 측면

  • 자본 및 운영 비용 절감
  • 다운타임 최소화 (또는 제거)
  • 비즈니스 연속성 및 재해 복구 향상
  • 데이터 센터 관리 간소화
    • 절차와 비용 간소화 가능

🔗 우리의 관심

  • 개발한 소프트웨어의 배포, 테스트, 구성 관리 등에 (실제 물리적 하드웨어에 상관없이) 통일된 환경을 제공할 수 있음
  • 따라서 소프트웨어 통합/인도 프로세스의 자동화에 적용하기가 좋음

📌 서버 가상화 기술의 진화

🔗 가상 기계 (VM; Virtual Machine) 기반

  • 하이퍼바이저(hypervisor)를 이용 (또 다른 컴퓨터가 있는 것처럼)
  • Type 1: 네이티브(native) 또는 베어메탈(bare-metal) 형 - 어떤 Hardware가 있으면 그 위에 바로 hypervisor가 올라가 있는 형태, 그리고 그 위에 게스트 OS가 설치된 형태
    • 전가상화 (full virtualization)
    • 반가상화 (para virtualization)
  • Type 2: 호스트형 (hosted) - 하드웨어 위에 host OS가 있고 (windows, mac 등) 이 위에서 hypervisor(Oracle virtual box 등)가 실행됨. 이 위에 게스트 OS가 올라가서 가상화를 제공
  • 호스트: 다른 시스템을 가상화하여 실행하는 컴퓨터
  • 게스트: 호스트 시스템 위에 가상화되어 제공되는 (가상) 시스템

🔗 컨테이너 (container) 기반

  • 호스트 OS의 컨테이너 기술을 이용

📌 컨테이너 가상화 (Containerization)

한 단계 추상화 레벨을 높인 가상화 기법으로, 컨테이너를 이용하는 기법이다. 컨테이너 엔진(docker 엔진 등)이 가상의 런타임 환경이 제공하고, 각각의 응용 소프트웨어는 격리된 환경(각각의 컨테이너)에서 실행된다. type 2에서 hypervisor가 모사하고 있는 대상은 컴퓨터 하드웨어이다. 하지만 컨테이너 엔진이 모사하고 있는 대상은 하드웨어가 아니라 운영체제이다. 따라서 하이퍼바이저를 이용하는 가상화에 비해 가볍고 빠르다는 장점을 가진다. 그러므로 우리는 컨테이너를 이용한 가상화를 널리 이용하고 있다.

📌 컨테이너 사용의 이점

  • 가상 기계 (VM; Virtual Machine)의 대체 또는 보완 방식으로 각광받고 있음
  • 소프트웨어 개발 및 배포의 효율과 안정성을 향상시킴
    • 응용 프로그램, 설정 파일, 라이브러리, 그리고 이들 사이의 의존성 관계를 한데 묶어 관리
    • 이 "묶음"을 컨테이너라고 부르고,
    • 컨테이너 엔진의 도움으로 시스템 의존성이 최소화되어 소프트웨어 시스템의 이식이 용이해짐

가상 머신은 일관성 있는 런타임 환경, 애플리케이션 샌드박스화 라는 이점을 가지고 있다. 컨테이너는 일관성 있는 런타임 환경, 애플리케이션 샌드박스화, 디스크 용량 절감, 낮은 오버헤드의 이점을 갖고 있다.

📌 도커 (Docker)

  • 널리 이용되고 있는 컨테이너 기반 가상화 플랫폼
    • Linux, Windows, MaxOS 상에서 실행되는 컨테이너 엔진을 제공한다
      • 내가 사용하고 있는 host OS 위에 어디든지 올릴 수 있음.
    • AWS, GCP, Azure 등의 클라우드 컴퓨팅 인프라와 결합하면 더욱 유연한 운영이 가능하다

📌 도커를 이용한 소프트웨어 개발/배포

도커의 컨테이너 이미지는 레이어를 가진 구조로 되어있다. 그 위에 웹 서버를 얹는다. 그 위에 web app source를 개발하여 얹어 하나의 web용 하나의 컨테이너 이미지를 만든다. 이것을 컨테이너에 실행할 때에는 Docker Container에 겹겹이 레이어를 가지는 이미지의 형태로 가져다가 컨테이너 위에서 실행하게 된다. 실행하다가 더 고도화하고 싶어서 web app source가 변경되면 제일 위에 있는 레이어의 이미지만 배포함으로써 시스템 업데이트를 한다. 이러한 구조를 가지기 위해서 도커 이미지는 레이어들로 이루어진 형태를 가지고 있다.

📌 도커 허브 (Docker Hub)

도커 허브는 컨테이너 이미지에 대한 큰 라이브러리이다. 컨테이너 이미지는 컨테이너 위에서 실행할 수 있는 소프트웨어 라이브러리 구성 파일들의 묶음이다. 컨테이너 이미지들에 대해 원격 저장, 유지관리, 공유, 권한 관리 등을 효율적으로 행할 수 있는 온라인 서비스를 제공한다. 이로 인해 소프트웨어 개발/배포 프로세스의 효율성이 크게 증대한다.

📌 도커 설치

  • 하려는 일
    • 내가 가진 컴퓨터에 도커 엔진(Docker engine)을 설치해서, 도커를 이용한 실습 준비를 해보자.
  • 생각하고 있어야 할 것
    • 나중에 CI/CD 파이프라인 구축을 완성할 때는 "내가 가진 컴퓨터"가 아니라 클라우드 환경을 이용할 것
    • (그땐 이런 설치 과정은 내가 할 일이 아님)
  • 준비
    • 컴퓨터 (Linux, Windows, MacOS 중 하나)
    • 최소 및 권장 요구사항 확인

📌 Docker Desktop과 Docker Engine

  • Docker Desktop for Linux
    • GUI 제공 - 보다 간단한 컨테이너 및 서비스 관리가 가능
    • Docker Engine을 포함, 그러나 Windows 및 MacOS의 경우와 마찬가지로 VM 위에서 실행
  • Docker Engine for Linux
    • Docker는 Linux의 프로세스 컨트롤 그룹을 이용하여 호스트 커널의 서비스들을 이용하며 격리되어 실행
    • 여기에서는 이 방법을 활용하는 것으로 가정

📌 도커 엔진 (실행 상태) 점검

  • 명령어
docker info

📌 Hello world에서 벌어진 일들

  • 명령어
docker run hello-world


이 메시지들은 컨테이너 안에서 실행된 소프트웨어가 뱉어낸 것들이다. 이 컨테이너는 hello-world라는 이미지들로 만들어졌다. 그 위 메시지들은 도커 엔진이 출력한 메시지이다. 맨 처음에는 도커 허브에서 가져온다. 한 번 더 똑같은 명령을 입력하면, 바로 출력하는데 이것은 도커 엔진이 실행한 컨테이너가 출력한 메시지이다.

📌 도커의 구성 요소

Docker Client가 있고, Client 프로그램을 이용하지 않고 REST 형태의 API를 이용할 수 있도록 제공한다. 이 명령을 Docker Daemon이라는 프로세스가 받아서 컨테이너들을 만든다거나 이미지를 만드는 일들을 수행한다. 이러한 모습으로 도커 시스템이 구성되어 있다. 이미지라는 컨테이너는 실행 가능한 컨테이너를 만들기 위한 거푸집이고, 실제로 이것을 가지고 만들어진 것이 컨테이너이다. 컨테이너는 도커가 실행하는 격리된 환경과 그 내부를 말한다.

Docker Client로부터 Docker Daemon에게 명령을 통해서 접근할 수 있고, REST 형태의 API를 제공하고 있어서 API를 통해서도 접근할 수 있다. Docker Daemon이 실행하고 있는 기계를 Docker Host라고 부르고 Docker Daemon은 Docker Host 위에서 실행하면서 도커 이미지들과 컨테이너들을 관리하는 일을 하고 있다.



📁 도커 이미지와 도커 컨테이너

📌 이미지와 컨테이너

🔗 도커 이미지 (Docker images)

  • 응용을 실행하는 데 필요한 모든 파일들과 그것을 실행하는 방법을 한데 묶어 놓은 것
  • 상태를 저장하지 않는 (stateless) 방식 - 네트워크로 전송, 레지스트리에 저장, 이름 및 버전 지정 가능
    • 이미지에는 실행 상태가 전혀 들어있지 않음 (컨테이너에서 관리)
  • 계층화되어 있다는 특징을 갖고 있으며, 어떤 이미지로부터 다른 이미지를 만드는 것이 가능
    • 이미지는 레이어 구조임

🔗 도커 컨테이너 (Docker containers)

  • 이미지의 실행 인스턴스 (instance)
  • 실행 상태를 유지함
  • 하나의 이미지로부터 여러 컨테이너 (인스턴스)를 만들어 동일한 응용을 여러 개 실행할 수 있음 (각각은 독립)
  • 상태를 저장하는 (stateful) 방식 - 컨테이너를 사용하면서 상태를 변경할 수 있음
    • 그러나 컨테이너가 소멸하면 이 상태도 잊어버림

📌 정리

  • 도커 이미지를 이용해서 컨테이너를 만들어 실행할 수 있다.
  • 도커 이미지는
    • 계층 구조를 가지고 있음
    • 컨테이너를 만드는 데 이용되는 거푸집으로서 상태를 저장하고 있지 않음
    • 이미지 레지스트리를 통하여 네트워크를 통해 전송 가능
  • 도커 컨테이너는
    • 이미지를 이용하여 만들어진, 응용 소프트웨어를 실제로 실행하는 격리된 환경
    • 도커 엔진에 의해서 관리되며 마치 컴퓨터 하나가 새로 생겨서 정해진 일을 수행하는 것과 같은 모습을 보여줌

📌 컨테이너와 이미지 관련 명령어 요약

docker run <이미지 이름>
  • 이름이 주어진 이미지를 로컬에서 또는 레지스트리에서 가져다가 컨테이너를 만들어 실행
docker ps, docker ps -a
  • 현재 실행 중인 (또는 중단되어 있는 것까지 포함하여) 컨테이너들의 정보를 조회
docker images
  • 로컬 컴퓨터에 가지고 있는 이미지들의 정보를 조회
docker stop <컨테이너 이름/ID>
  • 현재 실행 중인 컨테이너의 실행을 중단
  • 컨테이너가 없어지지는 않음
docker rm <컨테이너 이름/ID>
  • 컨테이너를 삭제
docker rmi <이미지 이름/ID>
  • 이미지를 삭제


📁 도커 이미지 만들기

📌 도커 이미지와 도커 컨테이너

도커 컨테이너는 이미지의 실행 인스턴스로서 실행 상태를 유지한다.

  • 이 "상태"를 조정해서 우리가 원하는 것을 만들 수 있는지 시도해보자.
  • 변경한 상태를 반영하는 이미지를 만들 수 있겠지, 당연히?
  • 이 과정을 자동화하는 방법을 알아보자!

📌 실험 계획

  • 상태를 깨끗하게 하고
    • 이전에 가져왔던 이미지, 실행했던 컨테이너들을 모두 삭제
  • httpd 이미지를 가져다가 실행하되
    • "It works!"말고 다른 기본 페이지가 나오도록 설정
    • 컨테이너 안의 특정 파일을 수정하는 작업
  • 이 상태로 실행되는 이미지를 작성
    • 이후에는 이 이미지로 컨테이너를 만들어 실행하면 항상 우리가 원하는 문서가 기본 페이지로 제공되도록

실습을 할 때 무한 로딩이 되어서

docker run -it -p 8080:80 httpd /bin/bash

이 명령으로 실행하였다.

📌 이미지 생성 자동화

  • Dockerfile
    • 계층 구조를 이용하여 도커 이미지를 만드는 절차를 기술하는 파일 (텍스트)
    • FROM [--platform=<platform>]<images>[AS<name>]
    • RUN <command>
    • ENTRYPOINT ["executable", "param1", "param2"]
  • 이미지 빌드 명령어
    • docker build [OPTIONS] PATH|URL|-

📌 이미지 레지스트리에 올려보자

📌 요약 정리

  • 도커의 편리함 (CI/CD 관점에서 생각해보기)
    • 응용을 실행하는 데 이용되는 실제 (물리적) 컴퓨터 환경과 독립적으로 통일된 실행 환경 제공 가능
    • 이미지로부터 여러 개의 동일한 컨테이너 인스턴스를 만들고 실행 가능
    • 필요한 소프트웨어 도구 및 설정 파일 등을 사전에 지정해 두고 알려진 상태로 컨테이너 생성 가능 (자동화 가능!)
  • 남아있는 일들
    • 환경 변수의 이용
    • 컨테이너들 사이 및 호스트와 컨테이너 사이에 TCP/IP를 이용한 통신 가능하게 하기
    • 호스트와 컨테이너 사이의 볼륨 공유
    • 도커 클린업

📌 실습

🔗 간단한 도커 응용 만들기 - 이미지 이름(과 태그)는 hello:0.1

  • 베이스 이미지 : ubuntu:22.04
  • 패키지 설치 : python3(apt-get 이용)
  • 응용 스크립트 설치: hello.py

🔗 로컬 이미지 이용하여 컨테이너 만들고 실행

  • docker run hello:0.1


📁 컨테이너 다루기

📌 도커에서 환경 변수의 이용

  • 환경 변수를 참조하도록 hello.py를 수정
import os
print("Hello World from %s!" %os.environ["NAME"])
  • Dockerfile 내에 ENV 지시자를 이용하여 환경 변수 내용 지정 (FROM 보다 바로 뒤에)
    ENV NAME Grepp
FROM ubuntu:22.04

ENV NAME Grepp

RUN apt-get update && apt-get install -y python3
COPY hello.py .

ENTRYPOINT ["python3", "hello.py"]
  • 이미지 빌드 (hello:0.2)하고 실행해서 결과 확인

📌 명령어 라인에 환경 변수 지정

명령어 라인에 환경 변수 내용을 지정하면 Dockerfile의 내용보다 우선 적용됨

📌 실행이 끝난 컨테이너의 자동 삭제

docker run 명령에 --rm 옵션을 붙이면 실행 완료와 함께 컨테이너 삭제

📌 백그라운드

docker run -d --rm -p 8080:8080 tomcat

docker inspect [ID]

명령어를 통해 IPAddress를 얻을 수 있음

📌 호스트에서 컨테이너에 접속할 수는 있으나

tomcat이 실행되고 있는 컨테이너의 TCP/8080 포트를 호스트의 외부로부터도 접속 가능하도록 (서비스를 실행했다고 가정해보자) 설정하려면?
→ 호스트의 특정 포트를 특정 컨테이너의 특정 포트와 연결하는 방법이 필요

지금은 호스트 네트워크 인터페이스와 컨테이너 사이의 연결이 없음

docker run -p <호스트 포트>:<컨테이너 포트>
  • -P(대문자) 옵션은 호스트의 사용하지 않고 있는 포트를 자동으로 할당하여 연결한다.

📌 컨테이너 이름 지정하기

  • 도커 컨테이너는 이름과 ID (고유 해시 값)에 의하여 식별
    • 이름을 지정하지 않으면 docker가 컨테이너를 만들 때 이름을 자동 부여
    • 그러나 관리 편의 및 자동화를 위해서 이름을 지정하는 것이 필요해짐
  • 명령어
    • docker run --name <컨테이너 이름> <이미지>

📌 도커 클린업

  • 컨테이너 삭제
    • docker rm <컨테이너>
  • 이미지 삭제
    • docker rmi <이미지>
  • 컨테이너 전체 삭제
    • docker container prune
  • 이미지 전체 삭제
    • docker image prune -a

📌 요약

  • 이 강의에서 배우고 실습한 것들
    • 도커 컨테이너에 환경 변수 전달 (두 가집 방법)
    • 백그라운드로 컨테이너 실행하는 방법, 실행 마친 컨테이너가 자동 삭제되도록 하는 방법
    • 호스트의 포트를 컨테이너의 포트에 연결하여 컨테이너 안에서 실행되는 서비스를 바깥으로 노출하는 방법
    • 컨테이너의 이름 지정하기, 삭제하고 정리하기, 이미지 정리하기
  • 다음 강의에서 배우게 될 것
    • 컨테이너 안에 어떤 파일을 넣고 싶은데...(특히, 이미지 만들 때 파일들 배치는 중요)
    • 컨테이너와 호스트 사이에 파일들을 공유할 수 있으면 좋을 텐데...


📁 컨테이너 안의 파일들과 도커 볼륨

📌 컨테이너 안의 파일들에 접근하는 방법

  • 실행하고 있는 컨테이너와 호스트 사이의 파일 복사
    • 명령어 docker cp를 이용
  • 이미지 빌드할 때 호스트로부터 파일을 컨테이너에 추가
    • Dockerfile 안에 ADD 지시자를 활용
  • 바인드 마운트
    • docker -v 옵션으로 호스트의 특정 디렉토리를 컨테이너와 공유
  • 도커 볼륨
    • docker -v 옵션으로 호스트와 공유하는 것은 비슷하지만 컨테이너가 마운트하는 것은 추상화된 볼륨

📌 컨테이너 안의 파일들 다루기

🔗 실습 준비

  • nginx:latest 이미지로 컨테이너를 실행하되, 컨테이너의 80포트를 호스트의 8080 포트에 연결
  • 호스트에서 브라우저 실행하여 localhost:8080 주소에서 웹 접속 성공하는지 확인
    • 보다 확실히 하고자 한다면, 컨테이너를 종료하고 접속 안 되는 것도 확인

대체할 파일을 하나 준비

  • 기본으로 표시되는 내용과 식별되는, 간단한 html 파일을 하나 준비해서 이것을 컨테이너에 보낼 준비
docker run --rm -d -p 8080:80 --name my_nginx nginx:latest
docker exec -it my_nginx /bin/bash
dir /usr/share/nginx/html
docker cp index.html my_nginx:/usr/share/nginx/html


대체할 파일 생성

docker cp my_nginx:/usr/share/nginx/html/50x.html .
more 50x.html

📌 이미지 빌드에 파일 추가

  • Dockerfile 내에 ADD 지시자를 이용해서 호스트가 제공하는 파일을 특정 위치에 둠
    • ADD <호스트 내 source 파일의 경로> <컨테이너 내에 배치할 파일의 경로>
docker run --rm -d -p 8888:80 --name my_nginx your_nginx

📌 바인드 마운트 (bind mount)

  • 명령어
    • docker run -v <호스트 경로>:<컨테이너 경로> <이미지>
    • 호스트에 지정된 경로와 컨테이너의 지정된 경로가 서로 같은 내용을 공유하게 된다
  • 실습
    • 호스트에 실험용 디렉토리를 하나 만들고, 이 안에 간단한 텍스트 파일 하나를 생성
    • 이미지 ubuntu:22.04interactive/tty모드로 하여 /bin/bash 실행하되, 위 디렉토리를 볼륨 공유
    • 컨테이너 안에서 새로운 파일 하나를 생성, 컨테이너는 종료
    • 호스트에서 새로 생성된 파일 확인
This is a test file called A. txt.
docker run -it -v C:\Users\adray\work\vol:/host_directory ubuntu:22.04 /bin/bash

📌 도커 볼륨 이용

  • 볼륨 생성 명령어
    • docker volume create <볼륨의 이름>

0개의 댓글