10 minute read

16주차에 학습하였던, DevOps의 개념 및 구현을 위한 도구의 학습내용을 정리하였습니다.

개발

개발 방식의 종류

  • 컴파일러
    • Compiler: 개발자가 작성한 코드를 기계어로 변환
    • 기계어: 0과 1. 실행파일 형태로 작성된 코드
    • 실행 효율이 높음
    • 컴파일 과정이 필요
  • 인터프리터
    • Script의 내용을 Interpreter가 해석
    • 코드의 내용을 라인 단위로 해석하여 실행
    • 별도의 컴파일 과정이 필요하지 않음
    • 실행 효율 등은 낮음

개발 과정

요구사항 분석
소프트웨어 설계
구현
테스트
배포
유지보수

  1. 요구사항 분석
    • 필요로 하는 목표를 탐색
    • 개발 가능 여부
    • 비용/예산 등
  2. 소프트웨어 설계
    • 기능 구현을 위한 논리적 설계, 구조 설계
    • 개발 언어 및 운영 플랫폼
    • 인터페이스
  3. 구현
    • 설계에 따른 프로그래밍
    • 역할 및 업무 분담에 따른 협업
  4. 테스트
    • 기본적인 요구사항에 대한 동작 확인
    • 오류 확인
    • 변경된 요구사항에 대한 반영
  5. 배포
    • 개발된 제품을 운영환경으로 반영
    • 모니터링
  6. 유지보수
    • 추가 요구사항에 대한 반영, 시스템 장애 및 오류에 대한 대응

전통적인 개발 방식의 한계점

  • 코드 통합의 문제
    • 각자 작성한 코드를 통합하는 과정에서 다수의 문제가 발생
    • 테스트 환경 구성 및 코드 통합 작업 등에서 많은 시간이 소요
  • 버전 관리
    • 소스코드 개발 단계 및 테스트 단계에서 버전의 관리가 되지 않을 경우
  • 커뮤니케이션
    • 역할 간 소통 부재로 인한 장애 발생

DevOps

  • Development(개발) + Operations(운영)
  • 전통적인 개발 방식의 문제점을 해결하기 위한 노력
  • 문제점을 해결해 나가기 위한 일종의 ‘문화’
  • 상호존중, 실패에 대한 비난 금지, 긍정적인 자세

DevOps 실천방안

  • 마이크로서비스 아키텍처(MSA) ⇔ 모놀리식 아키텍처
  • IaC: Infrastructure as Code
  • 모니터링, 로깅
  • CI/CD
    • Continuous Integration
      • 지속적 통합
      • 코드 통합 등의 문제(Integration Hell)를 해결하기 위한 과정
      • 개발 코드 공유, 수시로 빌드를 통한 테스트, 자동화
    • Continuous Deploy
      • 지속적 배포
      • 변경된 코드에 대한 즉각적인 배포 수행
      • 자동화

CI/CD

  • 코드 관리(git)
  • CI(Jenkins)
  • CD(ArgoCD)

Jenkins

  • 2004년 Sun Microsystems회사의 코스케 가와구치 개발
  • 빌드 및 커밋 등의 불편함을 해결하기 위한 방법
  • Java 기반으로 동작하는 오픈소스
  • 과거에는 ‘허드슨’ Hudson 이라는 이름을 사용

Jenkins 설치

https://www.jenkins.io/doc/book/installing/linux
설치와 로그인 방법은 생략

Jenkins 환경 구성

  • 왼쪽 메뉴 Jenkins 관리 - Global Tool Configuration
    • JDK(Java Development Kit)
      • Install Automatically 체크 해제
      • JDK 설정 이름: JAVA_HOME
      • JDK 경로 : /usr/lib/jvm/java-11-openjdk-amd64
    • Git
      • Install Automatically 체크 해제
      • Git 설정 이름: Git
      • Git 경로 : git
    • Maven
      • Install Automatically 체크 해제
      • Maven 설정 이름: Maven_Home
      • Maven 경로 : /usr/share/maven
    • Maven plugin
      • Jenkins 관리 - Plugin 관리
      • maven integration
      • maven invoker

Maven

  • 빌드 및 테스트 도구
  • 수행 단계
    • clean : 빌드 관련 내용 정리(청소)
    • compile : 컴파일(빌드)
    • test : 빌드된 파일 테스트
    • package : 빌드된 파일을 JAR/WAR 생성
    • verify : 통합테스트
    • install : 로컬 저장소에 패키지 배포
    • deploy : 원격 저장소에 패키지 배포

Git

  • <참고> Git 관련 서적
  • https://www.oss.kr/oss_guide/show/2c619df7-40d6-43de-af7a-2b0db6c16538

git 명령을 사용하여 테스트 코드 데이터를 github로 push

  • git init
    • git 로컬저장소 초기화
  • git config
    • git 명령을 사용하여 접근할 계정에 대한 정보 설정
      • git config user.name
      • git config user.email
  • git add .
    • git 대상 파일 등록
      • . : 현재 디렉토리 내 전체 파일
  • git commit -m ‘my first build source code’
    • 변경된 내용을 추적하여 등록
      • m: 커밋 설명
  • git branch -M master
    • 현재 git의 branch 설정
  • git remote add origin <자신의 github="" repository="">
    • 원격 저장소(github)의 주소를 origin 이름으로 지정
  • git push origin master
    • master 브랜치의 데이터를 origin 저장소로 push
    • 인증 시 ID와 Access Token을 사용하여야 함

**<참고> git push 실행 시 인증정보 저장**

  • git config credential.helper store
    • 지속적인 저장
  • git config credential.helper cache
    • 일시적인 저장 (시간 경과시 삭제)

Tomcat Server를 사용한 WAR 어플리케이션 배포

  1. Tomcat EC2 인스턴스 생성 및 SSH 연결

  2. java jdk 설치
    • sudo apt update
    • sudo apt install openjdk-11-jdk
    • java –version
  3. Java 환경 구성
    • ~/.bashrc 파일 수정
       ...
       JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
       PATH=$PATH:$JAVA_HOME
      
  4. 쉘 설정 다시 로드
    • exec bash
    • echo $JAVA_HOME
    • echo $PATH
  5. Tomcat 및 Tomcat admin 설치
    • sudo apt -y install tomcat9 tomcat9-admin
    • sudo systemctl status tomcat9.service
  6. /etc/tomcat9/tomcat-users.xml 수정
  ... 
    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <role rolename="manager-jmx"/>
    <role rolename="manager-status"/>
    <user username="admin" password="admin" roles="manager-gui, manager-script, manager-jmx, manager-status"/>
    <user username="deployer" password="deployer" roles="manager-script"/>
    <user username="tomcat" password="tomcat" roles="manager-gui"/>
  </tomcat-users>
  1. 사용자 설정을 반영하기 위하여 tomcat9 서비스 재시작
    • sudo systemctl restart tomcat9.service
    • sudo systemctl is-active tomcat9.service
  2. 배포 작업 설정을 위한 Jenkins 플러그인 설치
    • deploy to container
  3. github repository, maven을 사용하여 빌드 및 tomcat 배포 작업 생성
    • jenkins 메뉴에서 새로운 item - Maven 프로젝트
    • deploy-to-tomcat - 소스코드 관리
    • github
      • repository: 자신의 github 레포지토리 주소
      • (선택)credential: 앞에서 생성한 credential 사용
    • 빌드
      • Root POM: pom.xml
      • Goals and options: clean install
    • 빌드 후 조치
      • deploy war/ear to container
        • WAR/EAR file : */.war (프로젝트 디렉토리 내 .war파일 지정)
        • Container: tomcat 9.x remote
          • Credential: deployer/deployer (새로 생성)
          • tomcat url: http://192.168.56.102:8080
  4. 배포 확인
    • jenkins 작업디렉토리(/var/lib/jenkins/workspace)
    • Tomcat 관리자 페이지
    • http://:8080/manager - 배포된 Tomcat 어플리케이션
    • http://:8080/webapp
  5. 컨텐츠 업데이트 후 갱신된 컨텐츠를 사용한 배포 테스트
    • 기존 컨텐츠 수정
    • /home/ubuntu/source-java-maven-hello-world/webapp/src/main/webapp/index.jsp
      <h1> Hello World </h1>
      <h2> Tomcat Deploy Test </h2>
      
          - github 소스 업데이트 적용
      
    • git commit -m “index.jsp modified(Tomcat)”
    • git push origin master - 앞 단계에서 생성한 jenkins 작업 재실행(Build Now) - Tomcat 페이지 접속하여 결과 확인 (http://:8080/webapp)

Jenkins를 사용한 Docker 컨테이너 환경 사용

  1. EC2 인스턴스 생성
    • 이름: Docker
    • IP: 192.168.56.103
  2. 인스턴스 연결 후 Docker 설치
    • sudo apt update
    • sudo apt -y install apt-transport-https ca-certificates curl gnupg lsb-release
    • curl -fsSL https://download.docker.com/linux/ubuntu/gpg sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    • echo “deb [arch=$(dpkg –print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable” sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    • sudo apt update
    • sudo apt install -y docker-ce docker-ce-cli containerd.io
  3. 현재 사용자 docker 그룹 추가
    • sudo usermod -aG docker $USER
  4. jenkins에서 docker 시스템으로 빌드 결과물을 전달하기 위한 플러그인 설치
    • Publish over SSH
  5. docker VM을 ssh로 연결하기 위한 ssh 설정 및 계정 패스워드 설정
    • sudo vi /etc/ssh/sshd_config
       ...
       PasswordAuthentication yes
       ...
      
    • sudo systemctl restart ssh.service
    • sudo passwd ubuntu
    • 암호 설정
  6. jenkins 인스턴스에서 docker 인스턴스로 ssh 연결 테스트
    • ssh ubuntu@192.168.56.103
  7. ssh 연결 설정 추가
    • 메인 UI - Jenkins 관리 - 시스템 설정- Publish over SSH (가장 아래쪽)
    • SSH Servers - 추가
      • name: docker-instance
      • hostname: 192.168.56.103 (docker VM IP)
      • username: ubuntu
      • ‘고급’ 버튼 클릭
        • Use password authentication, or use a different key : 계정 패스워드 설정 추가
        • Passphrase / Password: 암호 입력
  8. github repository, maven을 사용하여 빌드 및 tomcat 배포 작업 생성
    • jenkins 메뉴에서 새로운 item - Maven 프로젝트
    • copy-war-to-docker - 소스코드 관리
    • github
      • repository: 자신의 github 레포지토리 주소
      • (선택)credential: 앞에서 생성한 credential 사용 - 빌드
    • Root POM: pom.xml
    • Goals and options: clean install - 빌드 후 조치
    • Send build artifacts over SSH
      • SSH Server: docker-instance (이전에 생성한)
      • Transfer
        • Source files: webapp/target/webapp.war
        • remove prefix: webapp/target
        • remote directory: hello-world

Docker 이미지 생성

  1. 테스트용 Dockerfile (docker vm의 사용자 홈 디렉토리에서)
      FROM tomcat:9
      COPY ./hello-world/webapp.war /usr/local/tomcat/webapps
    
  2. 빌드 실행
    • docker build -t my-hello-world:latest .
  3. 이미지를 사용한 컨테이너 테스트
    • docker run -d –name test -p 8080:8080 my-hello-world:latest
  4. 빌드된 이미지를 사용한 어플리케이션 연결 테스트
    • http://:8080/webapp

Docker 컨테이너 배포를 위한 Jenkins 통합

  1. Docker 이미지 빌드를 위한 Dockerfile을 git에 포함 (git 저장소 위치에서 실행)
    • mkdir dockerfile
    • vi dockerfile/Dockerfile
       FROM tomcat:9
       COPY ./webapp.war /usr/local/tomcat/webapps
      
    • git add .
    • git commit -m “Dockerfile added”
    • git push origin master
  2. jenkins 작업 생성
    • jenkins 메뉴에서 새로운 item - Maven 프로젝트
    • deploy-to-docker - 소스코드 관리
    • github
      • repository: 자신의 github 레포지토리 주소
      • (선택)credential: 앞에서 생성한 credential 사용 - 빌드
    • Root POM: pom.xml
    • Goals and options: clean install - 빌드 후 조치
    • Send build artifacts over SSH
      • SSH Server: docker-instance (이전에 생성한)
      • Transfer 1
        • Source files: webapp/target/webapp.war
        • remove prefix: webapp/target
        • remote directory: hello-world
      • Transfer 2
        • Source files: dockerfile/Dockerfile
        • remove prefix: dockerfile
        • remote directory: hello-world
        • exec command
          docker build -t my-hello-world:latest ~/hello-world
          docker run  -d  --name my-hello-world-container -p 8080:8080 my-hello-world:latest
          
  3. 빌드 전 docker 인스턴스 내 테스트 환경 정리
    • 실행중인 컨테이너 제거
    • docker rm -f docker ps -aq - 빌드한 이미지 제거
    • docker rmi my-hello-world:latest - 이전 빌드 시 복사된 파일 및 테스트 파일 제거
    • rm -rf ~/hello-world
    • rm -f ~/Dockerfile

Ansible을 활용한 이미지 빌드 및 배포

Ansible을 배포작업에 포함하기

  1. 새로운 EC2 인스턴스 생성
    • 이름: Ansible
    • IP: 192.168.56.104
  2. ansible 인스턴스에 ansible 설치
    • sudo apt update
    • sudo apt -y install ansible
  3. ansible 인스턴스에 docker 설치
    • 이전 설치과정 참고
  4. ansible을 사용하여 작업을 제어할 수 있는 환경 구성
    • ~/.ansible.cfg
       [defaults]
       inventory = ./inventory.ini
      
    • ~/inventory.ini
       [ansible_host]
       192.168.56.104  ansible_connection=local
      
    • ansible 인스턴스에서 자신에게 ssh 키 기반 인증이 가능하도록 설정
    • ssh 데몬 설정에서 PasswordAuthentication 허용
      • sudo vi /etc/ssh/sshd_config
        • PasswordAuthentication yes
    • ssh 서비스 재시작
      • sudo systemctl restart ssh
    • ubuntu 사용자 패스워드 생성
      • sudo passwd ubuntu
    • ubuntu 사용자 키 생성 및 복사(ssh-keygen/ssh-copy-id)
      • ssh-keygen
      • ssh-copy-id ubuntu@192.168.56.104
    • ssh 패스워드 인증 해제
      • sudo vi /etc/ssh/sshd_config
        • PasswordAuthentication no
    • ssh 서비스 재시작
      • sudo systemctl restart ssh

Ansible 을 사용한 이미지 빌드 및 배포 작업 구성

  1. 간단한 테스트용 플레이북 작성 ``` —
    • name: Jenkins CI/CD test playbook hosts: ansible_host tasks:
    • name: image build command: docker build -t my-hello-world ~/hello-world
    • name: container create command: docker run -d –name my-hello-world-container -p 8080:8080 my-hello-world … ```
  2. 파일을 전달하기 위한 jenkins 작업 생성
    • jenkins 메뉴에서 새로운 item - Maven 프로젝트
    • deploy-to-docker-with-ansible - 소스코드 관리
    • github
      • repository: 자신의 github 레포지토리 주소
      • (선택)credential: 앞에서 생성한 credential 사용 - 빌드
    • Root POM: pom.xml
    • Goals and options: clean install - 빌드 후 조치
    • Send build artifacts over SSH
      • SSH Server: ansible-instance (이전에 생성한)
      • Transfer 1
        • Source files: webapp/target/webapp.war
        • remove prefix: webapp/target
        • remote directory: hello-world
      • Transfer 2
        • Source files: dockerfile/Dockerfile
        • remove prefix: dockerfile
        • remote directory: hello-world
  3. 생성한 플레이북 실행 및 재실행
    • ansible-playbook cicd.yaml
  4. 플레이북 수정
  ---
  - name: Jenkins CI/CD test playbook
    hosts: ansible_host
    tasks:
    - name: image build
      command: docker build -t my-hello-world ~/hello-world
    - name: container rm
      command: docker rm -f my-hello-world-container
    - name: container create
      command: docker run -d --name my-hello-world-container -p 8080:8080 my-hello-world
  1. 모듈을 사용한 방식으로 플레이북 수정
  ---
  - name: cicd with docker module
    hosts: ansible_host
    tasks:
    - name: Build an image
      docker_image:
        build:
          path: ~/hello-world
        name: my-hello-world
        tag: latest
        push: no
        source: build
    - name: Container started
      docker_container:
        name: my-hello-world-container
        state: started
        image: my-hello-world:latest
  1. docker 모듈 실행을 위한 패키지 설치
    • pip3 install docker-py
  2. docker 모듈을 사용한 플레이북 실행
    • ansible-playbook cicd-module.yaml
  3. 테스트 완료 후 테스트에 사용한 리소스 삭제
    • docker rm -f docker ps -aq
    • docker rmi my-hello-world
    • rm ~/*.yaml
  4. 작성한 플레이북을 git에 포함 (git 로컬저장소에서)
    • mkdir playbook
    • vi playbook/cicd-module.yaml
    • 위 플레이북 내용 입력 - git add . - git commit -m “ansible” - git push origin master
  5. jenkins 기존 작업 아래에 transfer 항목 추가
    • Transfer 3
    • Source files: playbook/cicd-module.yaml
    • remove prefix: playbook
    • remote directory: hello-world
    • exec command
      • ansible-playbook ~/hello-world/cicd-module.yaml

쿠버네티스와 jenkins 통합

  • jenkins: git로컬저장소 및 관리, 어플리케이션 빌드, CI/CD 구성 담당
  • ansible : 이미지 빌드, 이미지 push
  • k8s : 어플리케이션 파드 구동

이미지 빌드 후 컨테이너 생성 대신 이미지 업로드를 수행하는 플레이북

---
- name: cicd with docker module
  hosts: ansible_host
  tasks:
  - name: Build an image
    docker_image:
      build:
        path: ~/hello-world
      name: encore0511/my-hello-world
      tag: latest
      push: yes
      source: build
      #  - name: Container started
      #    docker_container:
      #     name: my-hello-world-container
      #     state: started
      #     image: my-hello-world:latest

이미지 삭제 후 다시 빌드하는 플레이북

---
- name: cicd with docker module
  hosts: ansible_host
  tasks:
  - name: Remove image
    docker_image:
      state: absent
      name: <dockerhub_ID>/my-hello-world
      tag: latest
  #  - name: Log into DockerHub
  #    docker_login:
  #      username: docker
  #      password: rekcod
  - name: Build an image
    docker_image:
      build:
        path: ~/hello-world
      name: <dockerhub_ID>/my-hello-world
      tag: latest
      push: yes
      source: build

쿠버네티스 리소스를 배포하기 위한 오브젝트 파일 작성 (git 로컬저장소에서)

  • mkdir manifest
  • vi manifest/deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-hello-world-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: my-hello-world
      template:
        metadata:
          labels:
            app: my-hello-world
        spec:
          containers:
          - name: my-hello-world-container
            image: <dockerhub_ID>/my-hello-world
            ports:
            - containerPort: 8080
              protocol: TCP
    
  • vi manifest/nodeport.yaml ``` apiVersion: v1 kind: Service metadata: name: my-hello-world-svc spec: selector: app: my-hello-world type: NodePort ports:
    • targetPort: 8080 port: 8080 nodePort: 30080 ```

이미지 빌드 작업 및 이미지 빌드 작업에 의해 트리거된 쿠버네티스 배포 작업 생성

  1. jenkins 작업 생성 (이미지 빌드)
    • jenkins 메뉴에서 새로운 item - Maven 프로젝트
    • docker-image-build - 소스코드 관리
    • github
      • repository: 자신의 github 레포지토리 주소
      • (선택)credential: 앞에서 생성한 credential 사용 - 빌드
    • Root POM: pom.xml
    • Goals and options: clean install - 빌드 후 조치
    • Send build artifacts over SSH
      • SSH Server: ansible-instance
      • Transfer 1
        • Source files: webapp/target/webapp.war
        • remove prefix: webapp/target
        • remote directory: hello-world
      • Transfer 2
        • Source files: dockerfile/Dockerfile
        • remove prefix: dockerfile
        • remote directory: hello-world
      • Transfer 3
        • Source files: playbook/build.yaml
        • remove prefix: playbook
        • remote directory: hello-world
        • exec command
          • ansible-playbook ~/hello-world/build.yaml
  2. jenkins 작업 생성 (쿠버네티스 배포)
    • jenkins 메뉴에서 새로운 item - Maven 프로젝트
    • deploy-to-k8s - 빌드 유발
    • Build after other projects are built
      • project to watch: docker-image-build
      • 실행옵션: Trigger only if build is stable - 빌드 후 조치
    • Send build artifacts over SSH
      • SSH Server: k8s-instance
      • Transfer 1
        • Source files: manifest/*.yaml
        • remove prefix: 없음
        • remote directory: 없음
        • exec command
          • kubectl apply -f ~/manifest
  3. 현재까지 작업된 내용을 git에 반영하고 docker-image-build 작업 실행 및 트리거된 배포 작업 확인

Github 업데이트에 따른 빌드 유발 설정 (Github Webhook)

  1. jenkins VM에서 인증에 사용할 키 설정
    • ssh-keygen -t rsa -f ~/.ssh/jenkins-github
  2. 생성된 키 중 public key 내용을 github에 저장
    • cat ~/.ssh/jenkins-github.pub
    • github 레포지토리 - setting - Deploy key에서 항목 생성하여 키 추가
  3. jenkins에서 생성한 키 등록
    • jenkins 관리 - manage credential
    • global 우측 화살표 클릭 - add credential
      • SSH username and private key 선택
        • ID: 키 이름 (임의로 입력)
        • username: 키 생성시 사용한 사용자
        • private key:
          • Enter directly
            • add 버튼 클릭 후 개인키 값 입력
            • cat ~/.ssh/jenkins-github
  4. jenkins 플러그인 설치: github integration

  5. 빌드 작업 구성에서 빌드 유발 항목 추가
    • 항목 체크: GitHub hook trigger for GITScm polling
  6. github webhook 생성
    • 레포지토리 설정 - webhook
    • URL: http://:8080/github-webhook/
  7. git 로컬저장소의 파일을 수정 후 push하여 webhook에 의한 docker-image-build 작업이 트리거되는지 확인

Categories:

Updated:

Leave a comment