[TIL 47일자] 데브코스 데이터엔지니어링

·2023년 6월 14일
0

데브코스

목록 보기
43/55
post-thumbnail

📚 오늘 공부한 내용

1. 웹서비스를 Docker로 구동해 보는 실습

1) 실습할 Hangman Repo 구성

app.py

  • flask의 메인 함수가 있고 command line으로 받은 포트를 바인드하고 요청이 들어오기를 기다림

requirements.txt

  • pip3 install requirements.txt로 설치 해당 프로그램 실행에 필요하여 설치해야 할 패키지들로 구성 (flask 모듈들 설치)
  • requirements.txt를 얻기 위해서는 pip3 freeze 명령어를 사용한다.

test.py

  • app.py에 있는 코드의 유닛 테스트 로직이 들어가 있으며 CI/CD 구성 시 실행이 되게 구성

README.md


2) Web Service 실행해 보기

  • cat requirements.txt
    • 설치되어야 하는 패키지가 어떤 것이 있는지 cat 명령어를 통해 requirements.txt에 기술된 내용을 보며 확인한다.
  • pip3 install -r requirements.txt
    • pip3 install requirements.txt만 실행하면 ERROR: Could not find a version that satisfies the requirement requirements.txt (from versions: none) HINT: You are attempting to install a package literally named "requirements.txt" (which cannot exist). Consider using the '-r' flag to install the packages listed in requirements.txt ERROR: No matching distribution found for requirements.txt이라는 오류가 발생한다.
    • requirements.txt 내부에 있는 패키지를 설치해야 한다는 것을 알려 주기 위해 -r을 붙여 주어야 한다.
  • python3 -m flask run --host=0.0.0.0 --port=4000
    - python을 통해 4000 번 포트로 해당 프로그램을 열어 준다는 뜻으로 localhost:4000으로 접속할 수 있게 포트를 열어 준다.

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

  • 만약 어떤 웹서비스를 Docker Container 내에서 실행한다면 특정 Port 번호를 오픈해야 한다.
  • 이때 Docker가 없으면 문제 없이 실행된다.
  • 그런데 만약 Docker Container 내에 특정 Port 번호로 실행된 Flask App이 있다면
  • 이 앱이 Container 밖에서도 실행될까?
    • Docker Container는 컴퓨터 안의 컴퓨터라고 생각하면 된다.
    • 그렇기 때문에 docker run으로 구동하여도 Container 밖에서는 실행되지 않는다.
    • Container는 완전 별개의 공간이라 바깥 프로세스는 읽을 수 없기 때문이다.
  • 이를 해결하는 방법은?
    • Port Forwarding 해 주어야 한다.
    • 밖에서도 Container 내부의 Port 번호가 보이게 해 주어야 하는데 다음과 같이 docker run -p 4000:4000 image_name Port 번호를 명령 시 같이 매핑해 주면 된다.

3) Dockerfile

  • python 파일이기 때문에 python을 FROM으로 설정
  • LABELkey-value 포맷으로 되어 있고, docker 이미지에 대한 메타데이터를 지정한다.
  • LABELdocker inspect 명령어를 통해 찾을 수 있다.
  • COPY 명령어를 통해 해당 위치에 뒤에 붙는 파일 app.pyrequirements.txt를 복사한다.
  • RUN을 통해 이미지 build 시 해당 명령을 실행한다.
  • EXPOSE PORT_NUMBER는 docker image가 실행될 때 이 포트 번호를 사용하니 포트 맵핑을 할 때 참고하라는 뜻이다. 실제 동작에는 전혀 관여하지 않는 명령 중 하나다.
FROM python:3.8-slim-buster
LABEL Maintainer="keeyong@gmail.com"
WORKDIR /app
COPY app.py ./
COPY requirements.txt ./
RUN pip3 install -r requirements.txt
EXPOSE 4000
CMD ["python3", "-m", "flask", "run", "--host=0.0.0.0", "--port=4000"]

4) Docker 실행

  • docker build -t docker_image_name .
    • docker 이미지를 실행하기 위해서 다음과 같은 명령어를 실행해 준다.
    • 만약 환경을 변경해 주어야 한다면 --platform=을 통해 수정해 준다.
  • docker inspect docker_image_name
    • docker 이미지 내의 여러 내용이 나오게 되고, Dockerfile에서 LABEL로 지정해 준 내용도 확인할 수 있다.
  • docker run docker_image_name
    • 이렇게만 실행하면 Container 내부에만 열리게 되므로 localhost:4000에 접속했을 때 오류가 발생한다.
  • docker run -p 4000:4000 docker_image_name
    • Container 외부에서도 실행되게 하기 위해서 -p port_number:port_number를 설정해 주어야 한다.
    • 이렇게 localhost 환경에서 프로그램을 확인할 수 있다.

  • docker stop container_id
    • 만약 컨테이너를 중지하고 싶다면 stop 명령어를 통해 중지한다.

2. 소프트웨어 빌드란?

  • 자신이 개발한 소프트웨어를 최종적으로 출시하기 위한 형태로 만드는 것이다.
  • 배포하기에 충분히 갖추어졌다고 생각할 때의 소프트웨어이므로 테스트가 굉장히 중요하다.
  • 테스트도 빌드의 중요한 일부로 포함된다.
  • 이때 가장 많이 사용되는 패키지 포맷이 Docker Image이다.
  • Unit Test, 통합 테스트 등 여러 테스트를 붙이는 것이 소프트웨어 안정성에 큰 영향을 끼친다.
  • 개발자가 코드를 변경할 때마다 테스트를 하는 것Continuous Integration라고 하며 이 역시 소프트웨어 안정성 증대를 위해 진행한다.

3. Continuous Integration이란?

  • Software Engineering Practice의 하나이다.
  • 코드 Repo는 하나만 유지한다. (Master) Master branch와 내가 개발하고 있는 branch를 자주 동기화해 주어야 한다. 그렇지 않으면 나중에 Merge 할 때 갭이 커져 문제가 발생할 수 있다.
  • 코드 변경을 최대한 자주 조금씩 반영해야 한다.
  • 테스트를 최대한 추가해야 한다. (Test Coverage)
  • 개발자가 코드를 변경한 것을 push 할 때마다 빌드를 자동으로 실행한다.
  • 성공한 빌드는 자동으로 배포한다. (CD: Continuous Delivery)

📌 CI/CD란?


Code Commit -> CI (테스트 수행) -> CD (소프트웨어 배포) -> 모니터링


4. Git이란?

  • Git분산 환경을 지원하는 소스 버전 컨트롤 시스템
  • SVN/CVS는 네트워크가 안 되는 환경이거나 보안 때문에 인증이 안 된다면 사용할 수 없는데 Git로컬에서 서버단 소스에 백업을 가지고 개발이 끝나면 서버단에 올리는 형태이기 때문에 네트워크가 안 되어도 혼자 개발할 수 있다.
  • 다만 분산 환경에서 돌아가기 때문에 사용법이 더 복잡하다.
  • 장점
    • 다수의 개발자 공동 개발
    • 코드 백업
    • 코드 리뷰 가능
    • 과거 코드로 롤백 가능 (버전 간 자유로운 이동 가능)

📌 Git 관련 용어

  • Repo: Repository의 줄임말로 Git으로 관리되는 소프트웨어 프로젝트
  • Master/Main: 한 Repo에서 기본이 되는 메인 코드로 Git에서 master이고 Github에서는 Main
  • Branch: 자신의 Repo에서 새로운 기능 개발을 위해 Master 혹은 다른 Branch로부터 만든 코드 작업본을 지칭 (원본 Branch와 병합하려는 목적으로 생성)
  • Clone: 다른 계정에 존재하는 repo로부터 새로운 local repository를 생성
  • Commit (Check in): 내가 만든 코드 변경을 Local Repository에 반영
  • Pull: Master와 같은 Remote Repo로부터 마지막 Pull 이후 변경된 것을 다시 가지고 오는 작업 (Master와 동기화)
  • Push: 작업 중인 Local Repo에서 Remote Repo로 복사하는 것
  • Merge: Pull이나 Push 했을 경우 두 Branch 가간의 충돌(Conflict)를 해결하는 과정 (직접 해결하기도 함)

5. Github란?

서비스**이다.

  • Git텍스트 Command Line 툴이지만 Github웹 기반 인터페이스도 제공한다.
  • 자신이 만든 repo들이 모두 public일 경우 사용이 무료이고, private repo는 개수에 따라 가격대가 결정된다.
  • 다양한 툴을 제공해 생태계를 마련한다.
    - Code 개발 생산성 증대를 위한 Copilot
    • CI/CD의 다양한 연동을 위한 Workflows
    • 문서화를 위한 Wikis
    • 버그리포트와 트랙킹을 위한 Issue

📌 Push나 Merge 시점이 CI/CD를 해야 할 순간

  • 코드가 main/master branch에 추가되는 순간 CI/CD를 트리거
  • 이때 테스트를 수행하고 최종적으로 Docker Image 등을 만들도록 하는 것이 가능
  • CI/CD는 Github에 구현하는 것이 가장 자연스러움
  • Github에는 Actions라는 기능을 통해 Workflow라는 이름으로 구현 가능

6. Github Actions이란?

  • CI/CD를 Github 위에서 구현하기 위한 서비스이다.
  • Workflow라 부르며 아래 컴포넌트로 구성된다.
    • Events
    • Jobs
    • Actions
    • Runner (내 서버를 사용하는지 Github를 사용하는지에 따라 비용이 달라짐)
  • Workflow는 트리거 이벤트가 발생하면 시작되는 일련의 동작들을 지칭한다
  • Workflow를 위한 명령어들은 YAML 파일로 저장된다.
  • Job들로 나눠지며 각 Job은 일련의 step을 수행한다.
    • 각 step은 하나 혹은 그 이상의 명령어를 실행한다. 이 명령어는 actions라고 부르는 명령어의 집합이 될 수도 있다.
    • 각 step은 윈도우나 리눅스 서버 위에서 runner에 의해 실행된다.

7. 테스트 추가 (Github Actions) - Python

1) Python Application

  • CI Template
  • 기본으로 pytest를 테스트 프레임워크로 설치한다.
  • 테스트 코드 실행 이외에 flake8을 이용하면 코딩 스타일과 문법 에러 체크도 가능하다.
  • flake8
    • Python 코드에서 에러나 코딩 스타일 등에서 이슈를 체크해 주는 툴
    • 이런 툴을 Linting Tool이라고 부르고, 언어별로 존재함
import random
def lower(a)
 return a.lower()
lower("aBC") # 테스트 출력 예
  • 이런 코드가 있을 때,
$ flake8 sample.py
  • 다음과 같이 실행해 주게 되면 sample.py:3:12: E999 SyntaxError: invalid syntax 오류를 안내해 주게 된다.

2) 테스트 코드

  • unittest를 사용하거나 pytest를 사용한다.
  • 최근에는 pytest를 더 많이 사용하고 있다.
  • 명령어를 실행할 때는 main이 되는 method가 정해지지 않았으면 python3 -m unittest test.py를 사용한다.
  • main method가 정해졌으면 python3 test.py를 사용한다.

3) yml, yaml 파일 포맷

  • 환경 설정 파일에 많이 쓰인다.
  • 기본적으로는 JSON과 동일하게 어떤 포맷을 표현할 수 있다.
  • Comments#과 같이 시작한다.
  • key-value의 구조라면 콜론과 공백을 사용해 준다.
name: John Doe
age: 30
  • List 형식을 표현하고 싶다면 이렇게 표현한다.
 hobbies:
  	- reading
    - hiking
  • Nested key-value를 사용한다면 두 번의 공백이 들어가게 된다.
contact:
	email: john.doe@example.com
    phone:
    	home: 555-1234
        work: 555-5678
  • multi-line string의 경우 콜론 뒤에 파이프(|)를 사용해 준다.
description:|
	This is a
    multi-line
    string

4) Git Actions

  • Git Actions를 주게 되면 Git Actions의 위치는 repo_name/.github/workflows/ 밑에 위치하게 된다.
  • yml 혹은 yaml 파일로 생성된다.
  • 이때 트리거 설정을 해 주게 되면 어떤 push가 일어나게 될 경우 다음과 같이 위에 표시가 된다.
  • 다 완료가 되면 초록색 체크, 그렇지 않으면 노란색 동그라미가 뜬다.
  • Detail을 눌러 더 상세한 내용을 볼 수 있다.

  • 테스트를 성공했는지 실패했는지 다음과 같이 확인할 수 있다.
  • 현재 unittest는 총 5 번의 테스트가 존재했으며 모두 성공한 것을 볼 수 있다.

8. 테스트 추가 (Github Actions) - Docker

  • Docker Image라는 템플릿을 사용해 준다.
  • Docker와 관련된 스텝들
    • docker login
      • docker hub ID와 Password를 읽어야 하는데 하드 코딩 하지 않고 Github 내에 저장한다.
        • secrets.DOCKER_USER
    • docker build
    • docker push

✍ 어떻게 Docker Hub의 ID와 PASSWORD를 Github 내에서 사용할 수 있게 저장할 수 있을까?

  • 먼저 settings를 선택해 준다.
  • Secrets and Variables를 선택해 준다. 이때 Secrets 밑에 두 개의 변수를 만들어 준다.
  • 다음과 같이 New repository secret를 통해 Secrets 밑에 Docker Hub의 ID와 PASSWORD를 저장(설정)해 준다.
  • 이렇게 생성된 변수는 ${{secrets.변수명}}을 통해 호출해 줄 수 있다.


🔎 어려웠던 내용 & 새로 알게 된 내용



✍ 회고

- CI/CD에서 Github를 사용하면 편리하게 사용할 수 있다는 것을 처음 알게 되었다. CI/CD 환경이 좋다는 것은 들었지만 직접 써 본 적이 없어서 더 그렇게 느꼈던 것 같다. git을 많이 활용해 보며 학습해야 되겠다는 것을 많이 느꼈다. 늘 Actions를 보면서 저건 뭘까라는 의문은 품었는데 오늘에서야 기능과 사용법을 알게 되었다는 게..

profile
송의 개발 LOG

0개의 댓글