본문 바로가기
Docker

Docker(3)

by 황밤 2023. 10. 10.
728x90
반응형

2023/10/10

1. docker file

1) 여러 프레임 워크의 docker file 작성

spring boot framework 의 docker file 생성해서 구동.

  • spring boot를 사용하기 위해서는 jdk, boot project 생성을 도와주는 IDE ( 이클립스, 기업에서 제공하는 IDE, intellij ) 가 준비되어 있으면 된다.
  • Java는 Gradle이나 Maven 이라는 빌드 도구가 있어 이 도구를 이용해 프로젝트를 빌드하기 때문에 python 처럼 의존성 라이브러리를 별도로 내보내서 설치할 필요가 없다.
  • 환경 설정
    • Jdk 설치. - java-version, javac -version
    • IntelliJ 설치.
    • Docker Engine 설치 - Docker Desktop으로 처리.
  • Spring boot application ( spring initializer) - 웹에서 생성 가능.
    • Spring web 의 의존성만 설정 후 생성.
  • 클래스 추가 후 코드 작성
  • 실행 해서 확인 - 브라우저에서 확인하거나 curl 명령으로 확인.
  • 프로젝트를 clean build : 터미널 창에서 빌드.
  • ./gradle build clean
  • 프로젝트 루트 디렉토리에 docker file 을 생성해서 작성 - 기본이 Dockerfile 이고 다른 티렉토리에 존재하거나 이름이 다르면 빌드를 할 때 -f 옵션을 이용해 경로를 설정
    • FROM 기본이 되는 이미지 이름.
    • FROM amazoncorretto:17 CMD ["./mvnw","clean","package"] ARG JAR_FILE=target/*.jar COPY ./build/libs*.jar app.jar ENTRYPOINT ["java","-jar","app.jar"]
    • 이미지 생성
      • docker build -f Dockerfile -t docker-example:0.0.1
      • docker image - 이미지 확인.
    • 컨테이너 생성
      • Docker run -p 8080:8080 --name:springapp docker-example:0.0.1
        • Docker build -t itbam/docker-example:0.0.1 -f Dockerfile
        • docker run -p 8080:8080 -dit itbam/docker-example:0.0.1 —name=springapp
      • 컨테이너 구동 여부 - docker ps
    • 접속 - 8080으로 포트포워딩을 했기 때문에 8080으로 접속한다.
  • Docker image를 이용해 클라우드에 배포.
    • 이미지 직접 업로드 or 도커허브에 업로드해서 경로를 설정해도 된다.
    • docker push itbam/docker-example:0.0.1

Node.js

  • Node Project를 docker file 을 이용해 구동 : node web(express)을 학습하고자 하는 경우 next.js 를 하는 것이 좋다
  • 환경설정
    • Node.js 설치.
  • Window : nodejs.org 에서 설치.
    • 실행 - package.json 파일의 script 부분을 수정.
    • const express = require('express'); const app = express(); app.set('port', process.env.PORT || 3000); app.get('/', (req, res) => { res.send('Hello, Express') }) app.listen(app.get('port'), () => { console.log(app.get('port'), '번 포트에서 대기 중') })
  • 이후 dockerfile 작성
    • 이미지 빌드 : docker build -t nodeapp .
    • 컨테이너 생성 및 실행 : docker run -d -p 3000:3000 --name=dockernode nodeapp
      • 이후 브라우저에서 3000번 포트 확인. (Hello Express)
  • FROM node RUN mkdir -p /app WORKDIR /app ADD . /app/ RUN npm install ENV NODE_ENV development EXPOSE 3000 80 CMD [ "npm","start" ]
#노드 프로젝트 생성 – 디렉토리를 생성하고 npm init
# 2개의 패키지 설치(express, nodemon)
npm install express
# package.json 수정
{
"name": "nodeapp",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
}
}

2) 압축 파일 사용

  • Linux 는 tar 나 gz 확장자에 대해서는 압축을 해제하지 않고 사용 가능
  • Linux 에서는 tar 나 gz는 압축을 해제할 필요가 없습니다.
 

GitHub - brayanlee/webapp

Contribute to brayanlee/webapp development by creating an account on GitHub.

github.com

FROM ubuntu#필요한 패키지 설치
RUN apt-get update
RUN apt-get install -y apache2

#로컬 파일을 이미지 안에 복사
ADD webapp.tar.gz /var/www/html

WORKDIR /var/www/html

EXPOSE 2000 80

#아파치 서버 실행
CMD /usr/sbin/apachectl -D FOREGROUND
  • 이미지 생성 : Dockerfile 의 이름이 다르거나 다른 경로에 있으면 -f 옵션을 이용해서 경로를 작성하고 빌드
    docker build -t webapp:1.0 -f ./dockerfiles/Dockerfile .
  • 컨테이너 생성 : docker run -dit -p 8002:80 --name=webapp webapp:1.0
  • 확인 : localhost:8002

성공 완료 화면


html, css, javascript 만으로 구성된 웹 프로젝트가 있는 경우 디렉토리를 그대로 가져와도 되지만 압축된 형태를 이용해도 됩니다.

 



3) 이미지 용량 절감

  • ubuntu 이미지의 경우
  • 이미지를 절감할 수 있는 명령
  • apt-get clean -y 이나 apt-get autoclean -y: 설치에 사용한 패키지 라이브러리, 임시 파일 또는 오래된 파일을 삭제
  • apt-get autoremove -y : 다른 패키지들의 종속성을 충족시키기 위해 설치한 패키지를 삭제
  • rm -rfv /var/lib/apt/lists/* /tmp/* /var/tmp/*: 캐싱된 파일을 모두 삭제
    리눅스나 도커는 이전에 설치한 파일의 캐시를 가지고 있다가 다시 설치하는 경우 빠르게 설치하거나 빌드
    다단계 빌드
  • 방금 전에 만든 Dockerfile을 수정 - RUN 3개를 추가
    • RUN apt-get clean -y
    • RUN apt-get autoremove -y
    • RUN rm -rfv /var/lib/apt/lists/* /tmp/* /var/tmp/*
  • go나 c 의 애플리케이션을 이미지로 만드는 경우 go 나 c는 바로 실행 파일을 만들지 않고 목적 프로그램을 먼저 생성한 후 실행 파일을 만들어서 실행하는데 프로그램을 실행만 하는 경우 중간에 만든 목적 프로그램은 필요가 없는데 이미지로 바로 만들면 목적 프로그램도 이미지에 포함되서 이미지의 용량이 커지게 됩니다.
  • 이런 경우에는 최종으로 생성된 파일만 이미지에 포함되도록 해주어야 합니다.

4) go를 이용한 다단계 빌드

  • 설치 : https://go.dev/dl/ 에서 다운로드 받아서 사용
  • 설치 확인 : go version
  • go 를 만든 목적은 운영체제의 커널 개발을 개발하는 것이었는데 이는 더 이상 진행을 하지 않고 클라우드의 핵심이 되는 애플리케이션(kubenetes, docker 등) 개발에 go를 주로 사용
  • 다단계 빌드를 위한 디렉토리를 생성 - 이미지 빌드를 할 때는 디렉토리의 모든 내용을 읽어서 수행
package main
import "fmt"
func main(){
	fmt.Println("Hello GO")
}
// go는 사용하지 않는 언어를 import 할 경우 에러 발생
  • 실행
    • go build 소스파일경로 을 이용하면 실행 프로그램이 만들어집니다.
    • windows 에서는 main.exe 가 만들어지고 다른 운영체제에서는 main 이 만들어집니다.
    • 다른 플랫폼을 위해서 빌드를 할 때는
      • GOOS=운영체제 GOARCH=플랫폼 go build 소스파일경로
      • linux 에서 동작하는 프로그램을 생성 : GOOS=linux GOARCH=amd64 go build main.go
      • 바이너리 파일의 이름을 변경하고자 하는 경우 -o 옵션을 이용
        • go build main.go -o app.exe
  • Dockerfile 생성 후 작성
FROM golang:1.15-alpine3.12 AS gobuilder-stage
#작업 디렉토리 설정
WORKDIR /usr/src/goapp
#파일 복사
COPY main.go .
#go 소스 파일을 빌드해서 바이너리 프로그램을 생성
#주의할 점은 자신의 시스템이 아니라 도커의 시스템을 설정하는 거라서 linux
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /usr/local/bin/gostart



FROM scratch AS runtime-snykgoof/scratch-node
COPY --from=gobuilder-stage /usr/local/bin/gostart /usr/local/bin/gostart
CMD ["/usr/local/bin/gostart"]
  • go 라는 language를 가져가지 않고 프로그램을 실행시킬 수 있게 해주기 때문에 클라우드에서도 GO가 유리함.
  • c 나 go는 바이너리 파일을 만들기 때문에 실행을 할 때 c 나 go 컴파일러가 필요없음
  • 다단계 빌드를 이용해서 마지막 실행 파일만 가지고 이미지를 만들면 용량이 줄어듬
  • python 이나 node 나 java 는 바이너리 파일을 만들지 않고 줄 단위로 번역하면서 실행되던가 jvm 위에서 실행되므로 실행을 하기 위해서 무엇인가 더 필요함
  • 클라우드 환경에서는 실행되는 프로그램의 크기가 크다면 그 만큼 비용이 더 지출되므로 최근에 go를 많이 사용합니다.
  • 이미지 빌드
    • docker build -t goapp:1.0 .
  • 컨테이너 생성
    • docker run --name goapp goapp:1.0
C:\Users\USER\multistage>docker run --name goapp goapp:1.0
Hello GO

5) yaml(yml, 야믈) 파일 작성법

  • 기본 문법
    • 들여쓰기 : 2칸 or 4칸
map
  apiVersion: v1
  kind: Pod
  
array
  skills:
    - docker
    - kubenetes
    
주석
  #comment 내용
  • 숫자는 따움표 없이 표기
  • 문자열은 큰 따움표 안에 표기
  • boolean 은 true/false, yes/no - 대소문자 구분 안함
  • 줄바꿈은 | (마지막에도 줄 바꿈이 적용 shift + \)
  • |- 은 마지막은 줄 바꿈이 적용 안됨
  • > 은 빈 줄은 제외
  • key와 value 를 작성할 때 value 앞은 빈 칸이 필요
  • value 가 문자열인 경우 대부분 따옴표 없이 작성해도 되지만 :이 포함된 경우는 반드시 따옴표를 해야함.
    • windows_drive: c (가능)
    • windows_drive: "c" (가능)
    • windows_drive: c: -> 이 경우는 에러
  • 대부분의 경우 yaml 은 json 으로 변역되서 수행
  • json 으로 작성한 후 yaml 로 변경하거나 yaml 로 작성한 후 json 으로 변경 : https://www.json2yaml.com

https://www.json2yaml.com  

 

https://www.json2yaml.com

JSON x

www.json2yaml.com

 

 

 

6) git hub action을 이용한 docker hub 배포

  • 실행 가능한 application 생성 - main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println("Hello GO")
		time.Sleep(10 * time.Second)
	}
}
  • 빌드 : go build main.go
  • 실행 : ./main.exe
  • Dockerfile을 만들어서 이미지로 만들어지는지 확인
FROM golang:1.13-alpine as builder

RUN apk update & apk add git

WORKDIR /usr/src/app

COPY main.go .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .

FROM scratch 

COPY --from=builder /usr/src/app .
CMD ["/main"]
  • Dockerfile을 이용해서 이미지를 생성
    • docker build -t goapp:1.0 .
  • 컨테이너 생성
    • docker run --name goapp-deploy goapp:1.0
  • 콘솔에 10초 마다 Hello Go 을 출력함.
  • 현재 프로젝트를 git hub에 업로드
    • github 에 repository 를 생성 : gitaction
    • 현재 디렉토리에서 git init
    • 현재 디렉토리에서 git add .
    • git config --global user.name 유저이름
    • git config --global user.email 이메일
    • git commit -m "메시지"
    • git remote add 저장소이름(origin) gitURL
    • git push 저장소이름(origin) 브랜치이름(main)
  • git hub 에서 main.go 파일과 Dockerfile 이 업로드 되었는지 확인 (CI)
  • Git Hub 에서 Docker Hub 에 로그인 하기 위해서 Docker Hub 에서 Access Token 발급
    • DockerHub 이름 : itbam
    • AccessToken : (dckr_pat_BqeIOYNW*****Tw7Yc-********)
    • 업로드에 사용할 repository 생성 : gitaction
    • Git Action 만들기 : git hub repository 에서 action을 누르고 새로운 workflow를 생성해서 작성
name : GitAction
#어떤 이벤트가 발생했을 때
#cron 이면 주기적인 작업
on:
  push:
    branches: ["main"] #main 브랜치에 push 이벤트가 발생하면
  pull_request: 
    branches: ["main"] #main 브랜치에 pr 이벤트가 발생하면

jobs:
  build: 
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set Up Go
        uses: actions/setup-go@v3
        with:
          go-version: 1.15
      
      - name: Build
        run: go build -v ./...
        #with 과 run 이 언어마다 달라짐
      - name: Login To DockerHub
        uses: docker/login-action@v1
        with:
          username: itbam
          password: dckr_pat_ZKp0ClOZep8-qExXy-4eEExXG8w

      - name: build and releae to DockerHub
        env:
          NAME: itbam
          REPO: gitaction
        run: |
          docker build -t $REPO .
          docker tag $REPO:latest $NAME/$REPO:latest
          docker push $NAME/$REPO:latest
  • 코드의 내용을 수정하고 git pull 
  • 로컬 컴퓨터에서 docker run itbam/gitaction 을 수행해서 이미지를 컨테이너로 만들면 변경된 내용이 적용됩니다.
  • 소스 코드를 수정하고 github 의 소스 트리에 push나 pull request 를 git action에 설정된 내용이 수행됩니다.
    • 도커 허브에 업로드
    • 가장 많이 수행하는 작업이 도커 허브에 업로드 하거나 jenkins 를 이용한 build 나 public cloud에 전송하는 작업입니다.

7) git hub action 을 이용한 docker hub 배포

  • 동작하는 application 과 Dockerfile 작성
    • main.go 파일을 만들고 작성한 후 실행
    • go build main.go (main.exe 생성)
    • main.exe
FROM golang:1.13-alpine as builder

RUN apk update & apk add git

WORKDIR /usr/src/app

COPY main\.go .

#디렉토리 안의 go 파일 들을 빌드해서 main 이라는 바이너리 파일을 현재 디렉토리에 생성
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main .

#다단계 빌드 때문에 작성 
FROM scratch 
#앞의 builder 라는 FROM 절에서 /usr/src/app 디렉토리의 내용을 현재 디렉토리로 복사
COPY --from=builder /usr/src/app .
#main 을 실행
CMD ["/main"]

 

  • 이미지로 생성
    • docker build -t goapplication .
  • 컨테이너로 실행
    • docker run --name goapplication( 계속 동작해야 하는 경우 -dit, 외부에서 접근하면 -p 포트번호:포트번호) goapplication
  • 동작하는 application 과 Dockerfile을 git hub에 업로드
  • docker hub에서 access token을 발급받고(1번 발급 받은 것을 재사용 - 발급받을 때는 값을 확인 가능하지만 한 번 발급 받으면 다음 부터는 확인이 안됨.) repository를 생성
  • git hub 에서 git action을 생성(로컬 프로젝트의 .github 디렉토리의 workflows 디렉토리에 yaml 파일로 만들어서 업로드 해도 됩니다.)
  • git hub 업로드
  • docker hub 에서 access token 을 발급받고 (1번 발급 받은 것을 재사용 - 발급받을 때는 값을 확인할 수 있지만 한 번 발급 받으면 다음부터는 확인 안됨) -repository 생성
  • dckr_***_P-xQb0XWxU4so-cSugb5rOV**** (암호 토큰)
  • dckr_pat_P-xQb0XWxU4so-cSugb5rOVze4o
  • 소스 코드를 고쳤을 때 반영되는지 확인
    • 로컬 프로젝트에서 변경된 내용을 반영 : git pull origin main
    • 코드를 수정하고 push 한 후 이미지를 다시 다운로드 받아서 확인

2. Docker-Compose

2.1) 개요

  • 시스템 구축과 관련된 명령어를 하나의 텍스트 파일에 기재해서 한 번에 시스템 전체를 실행하고 종료와 폐기까지 한번에 하도록 도와주는 도구
  • 공통의 목적을 갖는 애플리케이션 스택을 docker compose yaml 코드로 작성하고 한 번에 서비스를 올리고 관리할 수 있는 도구
  • 데이터 베이스는 mysql을 사용하고 클라이언트의 요청은 node.js 를 이용해서 처리하고 클라이언트 애플리케이션은 react 로 배포하고자 하는 경우
    • 하나의 network 로 묶어서 배포하는 방식 : 권장하지 않음
    • 별개의 컨테이너로 배포한 후 네트워크로 연결하거나 포트 포워딩을 이용해서 접근 : 하나의 정의 파일을 이용해서 배포(docker-compose)
  •  yaml 포맷으로 기술된 설정 파일을 이용해서 여러 container 간의 실행이나 관계를 설정한 후 일괄 실행 또는 일괄 종료 및 삭제할 수 있는 도구
  • 도커 명령어와 유사하지만 도커 명령어는 아님

2.2) docker-compose 와 Dockerfile의 차이

  • Dockerfile은 하나의 이미지를 만들기 위한 것으로 네트워크 나 볼륨의 생성은 못함
  • docker-compose 는 docker run 명령을 여러 개 모아놓은 것과 같은데 컨테이너 주변 환경을 생성하고 네트워크와 볼륨까지 함께 만들 수 있음
  • kubenetes 를 학습한 경우에는 대부분 docker-compose를 사용하지 않고 kubenetes를 이용

2.3) 설치

  • Mac 이나 Linux 에서 Docker Desktop을 사용하는 경우는 별도의 설치가 필요없음
  • Linux 에서는 별도로 설치를 해야 함.

2.4) 샘플

  • apache web(httpd) 서버를 만들어서 실행
  • 명령어를 입력하는 방식 
    • docker run --name apa000 -d -p 8080:80 httpd
    • docker-compose.yaml 파일을 작성
version: "3"
services:
  apa001:
    image: httpd
    ports:
      - 8081:80
    restart: always
  • 명령어 : docker-compose up
  • docker ps 로 새로운 컨테이너가 생성되었는지 확인하고 브라우저에서 localhost:8081 로 확인
  • maria db 컨테이너 생성
    • 명령어를 이용
      • docker run --name mariadb -d -p 3306:3306 --restart=always -e MYSQL_ROOT_PASSWORD=root mariadb
      • docker-compose 이용
version: "3"
  services:
    mariadb:
      image: mariadb:10.4.6
      environment:
        - MYSQL_ROOT_PASSWORD=root
      ports:
        - 3306:3306
      restart: always

 

# 깔필요 없이 위 명령어들만 사용하면 docker를 통해 db를 사용할 수 있음.
그러나 직접 깔아서 환경 변수 설정하는 것은 클라우드를 해야할 때 해보는 것이 좋고
그 외의 경우는 명령어를 통해 수행하는 것이 좋다.

 

2.5) 작성 방법

  • 주 항목
    • services : 컨테이너
    • networks : 네트워크
    • volumes : 볼륨
  • 정의 내용
    • image
    • networks: --net
    • volumes : -v
    • ports : -p
    • environment : -e
    • depends_on : 다른 서비스에 대한 의존 관계, 다른 서비스를 먼저 실행시킬 때 사용(wordpress는 mysql이나 mariadb 와 같이 사용됩니다. 이런 경우 mysql 이나 mariadb 가 먼저 실행되어야 하므로 wordpress 컨테이너를 만들 때 depends_on 에 mysql 이나 mariadb 를 설정해주어야 합니다.)
    • restart : 컨테이너 종료 시 재시작 여부(no, always, on-failure, unless-stopped)
  • 버전 정의
    • yaml 코드의 첫 줄은 버전을 명시
    • 이 버전에 따라 지원하는 도커 엔진의 버전이 달라지게 됩니다.
    • 3.9 라고 설정하면 도커는 19.03 버전 이상이어야 합니다.
    • 3이라고 설정하면 거의 모든 도커 버전을 지원
    • 버전을 확인하면서 작성하는 것을 권장하는데 이유는 도커와 쿠버네티스는 업데이트 속도가 빠름

 

 

3)서비스 정의
=>컨테이너를 실행하는 것 과 동일한 개념
=>서비스 이름을 정의하고 하위 레벨에 도커 명령 과 유사하게 컨테이너 실행에 필요한 옵션을 작성

docker run --name=myweb nginx:latest
docker run --name=mariadb mariadb:10.4.6

version "3"
services:
    myweb:
       image: nginx:latest
    mariadb:
       image: mariadb:10.4.6
    

=>Dockerfile을 이용한 이미지의 경우
version "3"
services:
    myweb:
       build: .
    mariadb:
       build: 
          context:.
          dockerfile: 도커파일 경로

=>하위 옵션
    container_name: --name 과 같은 옵션으로 컨테이너 이름을 설정
    
    ports: -p 와 같은 옵션으로 포트포워딩 설정

    expose: 외부로 노출하지는 않고 필요 시 링크로 연결된 서비스 와 서비스 간의 통신을 허용할 때 사용하는 포트

    networks: --net 옵션 과 같은 옵션으로 하나의 네트워크로 묶을 때 사용

    volumes: -v 옵션과 같은 옵션으로 볼륨을 사용하고자 할 때 사용

    environments: -e 옵션 과 같은 옵션으로 환경 설정할 때 사용

    command: 서비스가 구동된 후 실행할 명령어를 작성

    restart: --restart 옵션과 동이하며 재시작 옵션

    depends_on: 서비스 간의 종속성을 의미하며 먼저 실행해야 하는 서비스를 지정

=>네트워크 정의
 네트워크: 여러 컨테이너들이 서로 연결될 수 있도록 해주는 것
 docker-compose는 네트워크를 지정하지 않으면 자체 기본 네트워크를 자동으로 생성
 최상위 레벨에 networks 지정 시 해당 이름의 네트워크가 생성되고 대역은 172.x.x.x(사설 IP)로 자동 할당됩니다.

=>볼륨 정의
 도커 엔진 내부의 공간 과 컨테이너 사이의 데이터를 공유하기 위한 것
 컨테이너 내부의 데이터를 반 영구적으로 보관하기 위한 목적으로 사용

6.도커 명령어 와 docker-compose 비교
=>데이터베이스는 mysql:8.0 을 사용하고 웹은 wordpress:5.7 을 이용하는 웹 애플리케이션 서비스
각 컨테이너는 각각의 볼륨을 소유하고 2개의 컨테이너는 하나의 네트워크로 묶어서 사용
이 작업을 할 때 wordpress 나 redmine 을 많이 사용하는데 이유는 wordpress 나 redmine은 mysql 이나 mariadb 가 연결이 안되면 에러를 발생시키기 때문입니다.

1)도커 명령어 사용
=>2개의 볼륨 생성
docker volume create mydb_data
docker volume create myweb_data

=>볼륨 확인
docker volume ls

=>네트워크를 생성
docker network create myapp-net

=>네트워크를 확인
docker network ls

=>MySQL 컨테이너 생성
docker run 
    -dit
    --name=mysql_app 
    -v mydb_data:/var/lib/mysql 
    --net=myapp-net 
    --restart=always 
    -p 3306:3306 
    -e MYSQL_ROOT_PASSWORD=wnddkd 
    -e MYSQL_DATABASE=adam 
    -e MYSQL_USER=adam 
    -e MYSQL_PASSWORD=wnddkd 
    mysql:8.0

 - 확인: docker ps
    docker ps 에서는 확인이 안되고 docker ps -a 에서는 확인이 된다면 컨테이너가 생성은 되었지만 실행 중 오류가 발생한 것이므로 옵션들을 확인해야 합니다.
    이미 사용 중인 포트인지 확인
    컨테이너 자체가 만들어지지 않으면 컨테이너 이름 이나 이미지 이름에 오류가 있는 경우
 - 포트 확인: 데이터베이스 접속 도구에서 3306 번으로 접속


=>WordPress 컨테이너 생성(로그 데이터는 사용자가 보아야 하는 데이터이므로 볼륨에 연결하지 않고 하드디스크에 직접 연결하기도 합니다.)
docker run 
    -dit 
    --name=wordpress_app
    -v myweb_data:/var/www/html  
    -v ./myweb-log:/var/log 
    --net=myapp-net 
    --restart=always 
    -p 8001:80 
    -e WORDPRESS_DB_HOST=mysql_app:3306 
    -e WORDPRESS_DB_NAME=adam 
    -e WORDPRESS_DB_USER=adam 
    -e WORDPRESS_DB_PASSWORD=wnddkd 
    --link mysql_app:mysql 
    wordpress:5.7

 - 확인: docker ps
 - 브라우저에서 localhost:외부에노출할포트번호

2)docker-compose.yaml 이용(확장자는 yml 도 가능)
=>빈 디렉토리 생성

=>디렉토리에 docker-compose.yaml 파일을 생성
version: "3.9"
services:
  mydb:
    image: mysql:8.0
    container_name: mysql_app1
    volumes:
      - mydb_data:/var/lib/
    networks:
      - backend-net
    restart: always
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: wnddkd
      MYSQL_DATABASE: adam
      MYSQL_USER: adam
      MYSQL_PASSWORD: wnddkd
  myweb:
    image: wordpress:5.7
    container_name: wordpress_app1
    volumes:
      - myweb_data:/var/www/html
      - ./myweb-log:/var/log
    networks:
      - backend-net
      - frontend-net
    restart: always
    ports:
      - 8001:80
    environment:
      WORDPRESS_DB_HOST: mydb:3306
      WORDPRESS_DB_USER: adam
      WORDPRESS_DB_PASSWORD: wnddkd
      WORDPRESS_DB_NAME: adam
    depends_on:
      - mydb

networks:
  frontend-net: {}
  backend-net: {}

volumes:
  mydb_data: {}
  myweb_data: {}

=>도커 컴포즈 실행: docker-compose up

=>도커 컴포즈 확인: docker ps

7.docker-compose 명령어
1)명령어
=>build: Dockerfile을 이용한 빌드 또는 재빌드
=>config: 도커 컴포즈 구성 파일의 내용 확인
=>create: 서비스 생성
=>down: 도커 컴포즈 자원을 일괄 정지 후 삭제
=>events: 컨테이너에서 실시간으로 이벤트 정보를 수신
=>exec: 실행 중인 컨테이너에 명령 실행
=>help: 도움말
=>images: 사용된 이미지 정보
=>kill: 컨테이너 강제 정지
=>logs: 실행 로그 정보 출력
=>pause: 컨테이너 서비스 일시 정지
=>port: 포트 바인딩된 외부로 연결된 포트 확인
=>ps: 실행 중인 컨테이너 서비스 출력
=>pull: 서비스 이미지 가져오기
=>push: 서비스 이미지 올리기
=>restart: 컨테이너 서비스 재시작
=>rm: 삭제
=>run: 실행
=>scale: 컨테이너 서비스에 대한 컨테이너 수 설정
=>start
=>stop
=>top: 실행 중인 프로세스 출력
=>unpause
=>up: 컨테이너 서비스 생성 과 시작
=>version

2)컨테이너 서비스 생성 및 시작 명령어
=>docker-compose  -f 파일경로 up [옵션]
-f 옵션은 docker-compose.yaml 파일의 경로가 현재 디렉토리가 아닌 경우 사용

=>옵션
-d(--detach): 데몬으로 실행, 백그라운드로 실행

--build: 컨테이너를 실행하기 전에 이미지를 빌드

--force-recreate: 설정 또는 이미지가 변경되지 않았더라도 컨테이너를 재생성

-t, --timeout: 컨테이너를 종료할 때 타임아웃을 설정하는 것으로 기본은 10초

--scale SERVICE이름=개수: 컨테이너의 수를 변경

--abort-on-conatainer-exit: 컨테이너가 하나라도 종료되면 모든 컨테이너를 종료


3)python 의 flask로 웹 페이지를 만들고 redis 로 웹 페이지 엑세스 카운트를 캐시해서 페이지에 출력
=>flask
경량의 파이썬 웹 프레임워크
자유도가 높음
모든 것을 프로그래머가 직접 작성

=>redis
인 메모리 데이터베이스
메모리에 존재하는 데이터베이스로 유사한 종류로 H2 가 있음
public cloud 들 도 이 서비스를 제공하는데 비용이 비쌈

=>레디스 컨테이너를 실행
docker run --name 이름 -d -p 6379:6379 redis

=>파이썬 애플리케이션 생성
 - 빈 디렉토리에 가상 환경 생성
    mkdir flaskweb
    
        cd flaskweb
    
    python3 -m venv ./venv(python3 대신에 python 이나 ./venv 대신에 venv 로 입력)

    venv/Scripts/activate(source vent/bin/activate) 명령 수행 - 안되면 venv/Scripts 로 들어가서 activate 를 입력하면 됩니다.

    프롬프트 앞에 가상 환경 이름이 보이는지 확인
 
 - 필요한 패키지 설치
    pip install flask
    pip install redis

 - 파이썬 파일을 만들어서 작성(app.py)      
 import time
import redis
from flask import Flask

#웹 애플리케이션 객체
app = Flask(__name__)

def web_hit_count():
    #redis 데이터베이스에 접속해서 hits 라는 키의 값을 1증가시켜서 리턴하는 함수
    with redis.StrictRedis(host='127.0.0.1', port=6379) as conn:
        return conn.incr('hits')

#아이피 와 포트번호(도메인) 만 가지고 요청할 때
@app.route("/")
def index():
    cnt = web_hit_count()
    return '''
        <h1 style="text-align:center; color:black;">docker-compose application
        </h1>
        <p style="text-align:center; color:deepskyblue;">Web Access Count:{}
        times </p>'''.format(cnt)

#어떤 IP를 사용해도 되고 9000번 포트로 접속해야 하고 개발 모드로 실행
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=9000, debug=True)

 - 파이썬 파일 실행: python 파일경로
   브라우저에서127.0.0.1:9000번으로 접속했을 때 카운팅이 되는지 확인

=>가상 환경에서 만든 파이썬 애플리케이션의 의존성을 requirements.txt에 작성
pip freeze > requirements.txt

=>파이썬 애플리케이션을 배포하기 위한 Dockerfile을 생성
FROM python:3.8-alpine
#캐시를 지우고 bash에 접속
RUN apk update && apk add --no-cache bash
#파이썬 관련 라이브러리 업데이트
RUN apk --update add python3 py3-pip python3-dev

#환경 설정
ENV LIBRARY_PATH=/lib:/usr/lib
ENV FLASK_APP=py_app
ENV FLASK_ENV=development

EXPOSE 9000
WORKDIR /py_app
COPY . .

#의존성 패키지를 설치
RUN pip install -r requirements.txt

#컨테이너로 만들어질 때 실행할 명령어
ENTRYPOINT ["python"]
CMD ["app.py"]

=>도커 파일이 제대로 만들어 졌는지 확인
docker build -t flaskapp .

docker run -dit -p 9000:9000 --name=flaskapp flaskapp

 

 

 

 

  • redis 와 flaskapp 을 동시에 컨테이너로 실행하는 docker-compose.yaml 파일을 작성
  • docker-compose 실행 : docker-compose -d up
  • 컨테이너를 묶어서 배포하게 되면 컨테이너가 먼저 만들어져서 외부 IP를 인식을 못하는 경우가 있으므로 이런 경우 내부 컨테이너에서 접속할 때 실제 IP가 아니라 127.0.0.1 이나 localhost를 사용하는 것을 고려해야 합니다.

7.4) 컨테이너와 네트워크 삭제 명령어

  • docker-compose -f 파일경로 down 옵션
  • 옵션
    • --rmi 종류 : 삭제시 이미지도 삭제
    • -v : 볼륨도 삭제

7.5) 종료

  • docker-compose stop
  • docker-compose rm
  • docker-compose down

8. Load Balancer

  • Load Balancing(부하 균등)
    • 동일한 기능을 수행하는 여러 개의 애플리케이션을 만들어 두고 요청이 오면 적절한 애플리케이션(하드웨어)을 선택해서 수행하도록 해주는 기능
    • 부하 분산을 위한 필수 네트워크 기술
    • 리소스 활용도를 최적화하고 처리량을 최대화하며 지연 시간을 줄이고 내결함성(fault tolerance) 구성을 보장해서 안정적인 시스템 운영이 가능하도록 합니다.
  • 도커는 HaProxy, Nginx/Apache 등 외부 서비스를 이용해서 로드 밸런싱을 구현하는 것이 가능

8.1) 로드 밸런싱 알고리즘

  • 라운드 로빈 알고리즘 : 클라이언트 요청을 서버의 가중치를 고려해서 구성된 서버에 균등 배분하는 방식으로 경로 보장이 안됨
  • 최소 연결(Least Connections): 현재 연결된 클라이언트 수가 가장 적은 서버로 요청을 전달, 경로 보장 안됨.
  • IP Hash : 해시 키를 이용해서 IP 별 index를 생성해서 동일 IP 주소는 동일 서버로의 경로를 보장하는 방식으로 해당 서버에 장애가 발생하면 주소는 변경되고, 균등배분 보장이 안되는 방식
    • 트랜 잭션이 긴 작업에 주로 이용 
  • General Hash : 사용자가 정의하는 키
  • 최소 시간(Least Time): 요청에 대한 낮은 평균 지연 시간을 기준으로 계산해서 서버를 지정
  • random 

8.2) 로드 밸런서 구현

  • 동일한 python flask 앱을 3개 만들고 앞에 nginx를 추가해서 클라이언트의 요청을 nginx 가 받아서 라우드 로빈 방식을 이용하여 각 flask 앱에게 전송
    • 원래는 모든 flask 앱이 동일한 모양이어야 하지만 편의상 보여지는 내용을 약간 다르게 구성
  • 디렉토리 생성
mkdir loadbalancer
cd loadbalancer

mkdir nginx_alb, pyfla_app1, pyfla_app2, pyfla_app3

#, 없어도 됨
  • nginx 작업
    • cd nginx_alb
upstream web-alb{
    server 172.17.0.1:5001;
    server 172.17.0.1:5002;
    server 172.17.0.1:5003;
}
server {
    location /{
        proxy_pass http://web-alb;

    }
}
  • pyfla_app1 작업
    • Dockerfile 생성
FROM python:3
COPY . .
WORKDIR /
RUN pip install flask
COPY . /
ENTRYPOINT [ "python" ]
CMD [ "app.py" ]

 

  • app.py 만들기

 

from flask import Flask

app = Flask(__name__)

app.route("/")
def index():
    return "Web Application [1]" + "\n"

#flask 의 기본 port 번호는 5000
if __name__ == "__main__":
    app.run(debug=True, host = "0.0.0.0")

 

  • pyfla_app2 작업
    • pyfla_app1 의 파일을 pyfla_app2 디렉토리로 복사
  • pyfla_app3 작업
    • pyfla_app1 의 파일을 pyfla_app3 디렉토리로 복사
  • 이후 각 파일의 내용의 번호만 바꿔 확인!
python app.py

docker build it flaskapp .
docker run -dit -p 5000:5000 --name=flaskapp flaskapp
  • loadbalance 디렉토리에 docker-compose.yaml 파일 생성 후 작성
  • 실행시, 각 각앱을 번갈아가면서 접속됨을 알 수 있음.
  • 브라우저에서 localhost:8080 접속
반응형
LIST

'Docker' 카테고리의 다른 글

Kubenetes  (1) 2023.10.19
Kubenetes(2)  (0) 2023.10.13
Docker  (2) 2023.10.04