230613 - Docker & K8S

김지석·2023년 6월 22일
0
post-thumbnail

Hangman 서비스 소개

Hangman 프로그램

  • https://github.com/learndataeng/hangman_web
  • hangman 프로그램을 flask를 사용하여 웹으로 노출
    • 포트번호는 어디든 바인딩 가능하며 실행할 때 지정
    • flask 관련 모듈 설치가 필요함: requirements.txt
  • 실행 방법
    • python3 -m flask run --host=0.0.0.0 --port=4000
      • 이 경우 app.py를 기본으로 사용함

Repo 구성 설명

app.py
-> flask의 메인 함수가 있고 커맨드라인으로 받은 포트에 바인드하고 요청 들어오기를 기다림
requirements.txt -> pip3 install -r requirements.txt flask 모듈들을 설치함
test.py
-> app.py 코드에 유닛 테스트 로직이 들어가 있음. CI/CD 구성 시 실행이 되게 구성할 예정
README.md

requirements.txt

Flask==2.3.2
Flask-HTTPAuth==4.5.0
Flask-Login==0.6.2
Flask-SQLAlchemy==3.0.3

-> pip3 freeze > requirements.txt

app.py

from flask import Flask,session
app = Flask(__name__)

…

app.secret_key = "Python Study"
if __name__ == "__main__":
	app.run()

프로그램 실행 데모

Hangman 서비스를 Docker Image로 구성

Docker 컨테이너 내부 프로세스와 호스트 프로세스간의 통신

  • Docker 컨테이너로 포트 4000에 실행된 Flask app이 있다
  • 이 app을 호스트 운영체제에서 접근하려면?

  • Docker 컨테이너 내부 프로세스가 오픈한 포트번호는 바깥 프로세스에는 안 보임
    • 예를 들어 앞서 4000번 포트는 호스트 프로세스 브라우저에게는 안 보임

  • Docker 컨테이너 내부 프로세스가 오픈한 포트번호를 외부로 노출해주는 것이 포트 맵핑 (포트 포워딩)
    • docker run 수행시 -p 옵션 사용
      • docker run -p 4000:4000 이미지이름

  • Docker 컨테이너를 실행할 때 포트 맵핑을 통해 호스트 운영체제 단에서 접근되는 포트를 컨테이너쪽으로 포워드해주어야함 -p 옵션
keeyong hangman % docker run -p 4000:4000 keeyong/hangman 
 * Debug mode: off
WARNING: This is a development server. Do not use it in a 
production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:4000
 * Running on http://172.17.0.3:4000
Press CTRL+C to quit

CI/CD와 Github Actions 소개

소프트웨어 빌드란?

  • 자신(팀)이 개발한 소프트웨어를 최종적으로 출시하기 위한 형태(패키지)로 만드는 것
    • 테스트가 빌드의 중요한 일부로 포함
  • 참여 개발자들이 많을수록 이는 더 중요
  • 개발이 끝나기 전부터 빌드를 하면 소프트웨어의 안정성 증대
    • Continuous Integration!

Continuous Integration이란?

  • Software Engineering Practice의 하나
  • 기본 원칙
    • 코드 Repo는 하나만 유지 (Master)
      • branch를 만들어 작업을 한 후 Master에 merge하기
    • 코드변경을 최대한 자주 반영
    • 테스트를 최대한 추가
      • Test Coverage
    • 빌드를 계속적으로 수행 (자동화)
      • Commit Build vs. Nightly Build
    • 성공한 빌드의 프로덕션 릴리스 (자동화)
      • CD: Continuous Delivery

빌드 실패

  • 새 코드의 커밋으로 인해 테스트가 실패하는 경우
  • 많은 회사들이 빌드 실패시 빌드가 다시 성공할때까지 코드 변경을 금지
    • 즉 빌드 실패는 모든 사람들을 잡아두는 족쇄
    • 그래서 어느 정도 조직이 커지면 빌드만 전담하는 엔지니어가 생김
      • 이 사람의 업무 중의 하나는 빌드 실패시 누가 주범인지 알아내는 것 ☺
    • 빌드 실패시 가벼운 형태로 페널티 부여

CI/CD

Git/Github

Git이란?

  • Git은 분산환경을 지원하는 소스 버전 컨트롤 시스템
    • CVS, SVN은 항상 서버에 연결되어 있다는 전제하에서 사용 가능 (중앙 개발)
  • 리눅스를 만든 Linus Torvalds가 개발
    • 리눅스 커널 개발을 위해 만들었으며 GPL v2 오픈소스
  • SVN/CVS에 비해 현저하게 빠르나 사용법은 훨씬 더 복잡함

Git의 장점

  • 다수의 개발자가 공동 개발
    • 팀원들과 코딩을 같이 할 수 있고 코드 충돌이 생기면 이를 해결가능하고
  • 코드 리뷰 가능
    • 코드변경을 주기적으로 저장하면서 리뷰를 받을 수 있고
  • 코드 백업
    • 모든 코드 변경이 기록되며
  • 과거의 코드로 롤백 가능
    • 지금 코드의 스냇샵을 잡아 (이를 버전이라 부름) 나중에 필요시 버전간 이동이 가능
  • 이 모든 작업을 꼭 코드 뿐만 아니라 모든 텍스트 파일에 사용 가능

Git 사용시 필요한 것

  • 직접 git을 사용한다면 git이 설치된 컴퓨터와 저장 공간
  • 클라우드 버전 사용 (GitHub, BitBucket, GitLab 등등)
    • 클라이언트는 별도 설치
    • Github이 가장 인기가 많음

Github이란?

  • Git repo 호스팅/클라우드 서비스 (http://github.com)
    • 대부분의 회사들이 Git을 직접 설치해서 사용하기 보다는 github을 사용
  • Git은 텍스트 커맨드라인 툴이지만 Github은 웹기반 인터페이스도 제공 (일부)
  • 자신이 만든 repo들이 모두 public일 경우 사용이 무료
    • private repo의 수에 따라 가격대가 결정됨
    • 개발자들을 위한 Facebook!
  • 다양한 툴을 제공하여 생태계 마련
    • Code 개발 생산성 증대를 위한 Copilot
    • CI/CD등의 다양한 연동을 위한 Workflows 제공
    • 또한 문서화를 위한 Wikis와 버그리포트와 트랙킹을 위한 Issues 기능을 제공
  • 2018년에 마이크로소프트가 $7.5B에 인수함

분산개발 vs. 중앙개발

Git 관련 용어

  • Repo:
    • Repository의 준말로 Git으로 관리되는 소프트웨어 프로젝트를 지칭
  • Master/Main:
    • 한 Repo에서 기본이 되는 메인 코드를 지칭. Git에서는 master이고 github에서는 이제 main
  • Branch:
    • 자신의 Repo에서 새로운 기능 개발등을 위해 Master 혹은 다른 Branch로부터 만든 코드 작업본을 지칭. 작업 후 나중에 원본 Branch와 다시 병합하려는 목적으로 만들어진다
  • Clone:
    • 다른 계정에 존재하는 repo로부터 새로운 local repository를 만드는 것
  • Commit (Check-in):
    • 내가 만든 코드 변경을 Branch의 Local Repository에 반영하는 것
  • 작업은 항상 내 컴퓨터에 있는 Local Repo에서 일어나며 Pull과 Push를 통해 서버상의 Remote Repo와 연결

  • Pull:
    • Master와 같은 Remote Repo로부터 마지막 Pull이후 변경된 것을 다시 가져오는 작업. 즉 Master(혹은 Branch)와 씽크하는 것을 지칭
  • Push:
    • 작업 중인 로컬 복사본 (Local Repo)에서 서버(Remote Repo)로 변경사항들을 복사하는 것을 지칭
  • Merge:
    • Pull이나 Push했을 경우 두 Branch(대부분 이 중 하나는 Master)간의 충돌(Conflict)을 해결하는 과정. 많은 경우 이는 자동으로 해결되나 몇몇 경우에는 손으로 직접 충돌을 해결해야 한다.

Main/Master 브랜치

● Github에서는 이전에 master라 불렀고 지금은 main이라 부르는 source of truth가 되는 특별한 branch
● 특정한 기능을 구현하기 위해 만들어진 mainline의 복사본. 구현과 테스트가 이뤄진 후에 main branch와 merge 됨.

Push나 Merge 시점이 CI/CD를 실행하기 위한 절호의 순간

  • 코드가 메인/마스터나 브랜치에 추가되는 순간 CI/CD를 트리거
    • 이를 특정 메인/마스터나 특정 브랜치만 대상으로 하도록 설정 가능
    • 이 때 테스트 수행하고 최종적으로 Docker Image등을 만들도록 하는 것이 가능
    • 그래서 CI/CD는 Github에 구현하는 것이 가장 자연스러움
  • Github에서는 이를 Actions라는 기능을 통해 Workflow라는 이름으로 구현 가능

Github Actions

Github Actions이란?

  • CI/CD를 Github위에서 구현하기 위한 서비스
    • 코드 테스트, 빌드, 배포 자동화 기능 제공
  • Workflow라 부르며 아래 컴포넌트로 구성
    • Events
    • Jobs
    • Actions
    • Runner
      • Github hosted runners
      • Self hosted runners

Github Actions - Workflow

  • Workflow는 트리거 이벤트가 발생하면 시작되는 일련의 동작들을 지칭
  • 트리거 이벤트의 예들은?
    • 코드 커밋 (main과 같은 특정 브랜치를 대상으로만 제한 가능)
    • PR 생성
    • 다른 Workflow의 성공적인 실행

Github Actions - Workflow

  • Workflow를 위한 명령어들은 YAML 파일로 저장
    • 명령어들로는 환경설정과 scripts 실행들이 대표적
  • Workflow는 Job들로 나눠지며 각 Job은 일련의 스텝을 수행
    • 각 스텝은 하나 혹은 그 이상의 명령어를 실행
      • 이 명령어는 actions라고 부르는 명령어들의 집합이 될 수도 있음
    • 각 스텝은 윈도우나 리눅스 서버 위에서 runner에 의해 실행
      • 이걸 Docker Image에서 수행하는 것이 서비스 배포 과정에 따라 더 일반적이기도 함

Github에서 어떻게 Github Actions를 선택하는가?

  • 적용하려는 repo에 보면 Actions 메뉴가 있음
  • 다음으로 workflow를 하나 생성
  • yml 파일을 직접 생성 혹은 템플릿(CI Templates) 선택 후 수정
    • Python Application 혹은 Docker Image

Github Actions 사용 #1: 테스트 추가

사용해볼 CI Template: Python Application

  • Python Application이란 CI Template을 사용할 예정
    • 테스트 코드 실행 이외에도 flake8을 사용해서 코딩 스타일을 체크해볼 예정
  • 기본으로 pytest를 테스트 프레임웍으로 설치 -> 우리는 unittest로 작성되어 있음
  • Python code linting tool으로 flake8을 설치하고 문법 에러와 코딩 스타일 체크

파이썬 코드 스타일 체크 - flake8

  • 파이썬 코드에서 에러나 코딩 스타일 등에서 이슈를 체크해주는 툴
    • 이런 툴을 Linting tool이라 부름 (언어별로 존재)
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics

sample.py :

def lower(a)
 return a.lower()
lower("aBC") # 테스트 출력 예

flake8 sample.py
-> sample.py:3:12: E999 SyntaxError: invalid syntax

테스트 코드 소개

  • 테스트 소스 코드
    • unittest를 사용 (pytest라는 대안도 있음)
  • 테스트 코드 실행

yml (or yaml) 파일 포맷

  • 환경설정 파일에 많이 쓰임
# Comments start with a #
# Key-value pairs are separated by a colon and a space
name: John Doe
age: 30
# Lists are denoted by a hyphen and a space
hobbies:
 - reading
 - hiking
# Nested key-value pairs are indented with two spaces
contact:
 email: john.doe@example.com
 phone:
 home: 555-1234
 work: 555-5678
# multi-line string
description: |
 This is a
 multi-line
 string
  • JSON과 사실상 동일하며 이들간의 변환도 가능함
  • JSON보다 비교적 타이핑을 덜 해도 된다는 장점이 있음.

.github/workflows/python-app.yml 설명

  • “on”: 트리거 이벤트 지정. main 브랜치에 push되거나 PR이 만들어지는 경우
on:
 push:
 branches: [ "main" ] # 모든 브랜치에 적용하고 싶다면 [ "main", "dev"]
 pull_request:
 branches: [ "main" ] # 모든 브랜치에 적용하고 싶다면 [ "main", "dev"]
  • jobs: 여기에 실제 CI 프로세스가 스텝(name)별로 기술됨. 여긴 빌드 하나임
  • requirements.txt가 있으면 이를 설치
  • 아래 녹색 부분만 수정. 코드 전체를 뒤져 test로 시작하는 모든 테스트를 실행

python-app.yml 파일을 PR로 추가

  • 커밋하고 변경을 새로운 PR로 생성
  • PR에서 머지하고 해당 브랜치 삭제

Github Actions 사용 #2 : Dockerization 추가

사용해볼 Template: Docker Image

● Docker Image이란 Template을 사용할 예정

Docker 관련 스텝들

Github Actions 사용 #2: 테스트 추가

  • docker login
    • 이 때 Docker hub ID와 Password를 읽어와야함. 하드코딩하지 않고 Github내에 저장
      • secrets.DOCKER_USER
      • secrets.DOCKER_PASSWORD
  • docker build
  • docker push

=> 위의 과정을 .github/workflows/docker-image.yml에 기술 (steps 밑에 name)

Docker Hub 정보 보관

  • Docker hub ID와 Password를 Github내에 저장
    • DOCKER_USER
    • DOCKER_PASSWORD
  • YML 파일 안에서는 아래로 접근가능
    • ${{secrets.DOCKER_USER}}
    • ${{secrets.DOCKER_PASSWORD}}

.github/workflows/docker-image.yml 편집

name: Docker Image CI
on:
 push:
 branches: [ "main" ]
 pull_request:
 branches: [ "main" ]
jobs:
 build:
  runs-on: ubuntu-latest
  steps:
  - uses: actions/checkout@v3
  - name: docker login
   env:
    DOCKER_USER: ${{secrets.DOCKER_USER}}
    DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
   run: |
    docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
  - name: Build the Docker image
    run: docker build --tag ${{secrets.DOCKER_USER}}/hangman:latest .
  - name: docker push
   run: docker push ${{secrets.DOCKER_USER}}/hangman:latest
profile
초짜에요...

0개의 댓글