0512_Docker_다양한 언어로 웹 이미지 빌드, Docker Hub 이미지 업로드, Docker Compose

HYOJU DO·2022년 5월 12일
0

Docker

목록 보기
2/3
post-thumbnail

이미지 빌드 시 제외할 파일 설정


🎈 이미지 생성 시 venv 등 가상 환경 생성 디렉토리 제거하고 커밋
➕ home 디렉토리나 root 디렉토리에서 이미지 빌드하면 안 됨

.dockerignore 파일


.dockerignore

*/temp*
*/*/temp*
temp?
*.md         # 모든 md 파일 제거
!README.md   # README.md 파일 제외하고 제거

.dockerignore

venv/
Dockerfile
.dockerignore



Flask 웹 이미지 빌드


작업 디렉토리 : ~/pythontest/flask

Dockerfile확인 TIP : 명령 실행

FROM python:3.9-slim-buster
COPY . /app
WORKDIR /app
ENV FLASK_APP hello
RUN python3 -m venv venv && . venv/bin/activate
RUN pip3 install -r requirements.txt
EXPOSE 5000
ENTRYPOINT ["python3", "-m", "flask", "run"]
CMD ["--host=0.0.0.0"]

이미지 빌드

docker build -t myflask .

실행

docker run -d -p 80:5000 myflask



Django 웹 이미지 빌드


작업 디렉토리 : ~/pythontest/Django

Dockerfile buster ver.

FROM python:3.9-buster
COPY . /app
WORKDIR /app
RUN python3 -m venv venv && . venv/bin/activate
RUN pip install -r requirements.txt

WORKDIR /app/mysite
CMD ["python3", "manage.py", "runserver", "0.0.0.0:8000"]
EXPOSE 8000

빌드

docker build -t mydjango .

실행

docker run -d -p 80:8000 mydjango

➕ alpine ver. slim-buster ver. Dockerfile
-> buster 버전에 비해 컴파일러 추가 설치 필요함

# alpine ver.
FROM python:3.9-alpine
RUN apk add gcc musl-dev

# slim-buster ver.
FROM python:3.9-slim-buster
RUN apt update && apt install -y gcc linux-headers

COPY . /app
WORKDIR /app
RUN python3 -m venv venv && . venv/bin/activate
RUN pip install -r requirements.txt

WORKDIR /app/mysite
CMD ["python3", "manage.py", "runserver", "0.0.0.0:8000"]
EXPOSE 8000

slim-buster, alpine 사용 시 발생하는 오류
-> gcc 패키지가 없음 (C로 만든 패키지 때문)

python에는 glue 가 있어서 다른 언어와 결합하여 사용 가능
추가 라이브러리 필요 시 설치



Golang 웹 이미지 빌드


Golang : 구글이 만든 오픈소스 컴파일 언어 (C 와 유사)
특징 : 쉬운 병렬처리, 포인터

작업 디렉토리 : ~/golang/hello

golang 설치

sudo apt install -y golang  # 설치 전 apt update

hello.go

package main

import "fmt"

func main() {
        fmt.Println("hello go world")
}

🎈 실행 방법 1
(시스템 자체에서 컴파일 한 후 실행)

go run hello.go

🎈 실행 방법 2

실행파일 컴파일

go build -o hello hello.go

빌드한 파일 정보 확인
(Go 는 기본적으로 static 빌드)

$ file hello

hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=kilVwbRvB5JBGs7k3hwb/XrzR3mHAdEcvAJSqkToW/CToig6r9T-tXro6I2j3g/5cUWIyuef7F7582S-bk_, not stripped

실행

./hello

Golang multi-stage 이미지 빌드

🎈 문장 출력하는 이미지

golang 이미지

Dockerfile

FROM golang:1.18-buster AS gobuilder
COPY hello.go /app/hello.go
WORKDIR /app
RUN go build -o hello hello.go

FROM scratch
COPY --from=gobuilder /app/hello /
CMD ["./hello"]

이미지 빌드

docker build -t gohello .

빌드한 이미지 실행

docker run gohello

생성 된 이미지 크기 확인 (1.76MB)

$ docker images | grep gohello
gohello                              latest               1da07d915b94   19 seconds ago       1.76MB

Golang 튜토리얼

Django의 프로젝트 & 앱 개념과 유사
go는 각각의 앱을 module 이라고 함

🎈 go.mod 파일이 없다는 오류 -> 모듈에 대한 정보가 없다는 것

go.mod 파일 생성
(프로젝트 - 앱 구조 생성)

go mod init [작업 디렉토리]

가능한 명령어 구조

go run .
go build .

or

go run hello.go
go build hello.go

Dockerfile

FROM golang:1.18-buster AS gobuilder
COPY hello.go /app/hello.go   
WORKDIR /app
RUN go build .

FROM scratch
COPY --from=gobuilder /app/hello /
CMD ["./hello"]

➕ COPY . /app/hello.go 로 설정 시, .dockerignore 파일 필수



Golang Web App 생성


작업 디렉토리 : ~/golang/goweb

mkdir goweb
cd goweb
go mod init goweb

goweb.go

package main

import (
    "fmt"
    "log"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) #  slicing : "/" 다음 내용 출력
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

r.URL.Path[1:] -> / 다음 내용만 슬라이싱
http://192.168.100.100/... 의 /부터 PATH 시작

실행

go run .

실행파일 빌드

go build .

빌드한 실행파일 크기 확인 (7.2M)

$ ls -lh goweb
-rwxrwxr-x 1 vagrant vagrant 7.2M May 12 11:38 goweb

.dockerignore

goweb/
Dockerfile
.dockerignore

dockerfile

FROM golang:1.18-buster AS gobuild
ENV CGO_ENABLED 0   # C 라이브러리 없기 때문에 C 구조체 참조 기능을 꺼야 정상적으로 작동
COPY . /app
WORKDIR /app
RUN go build .

FROM scratch
COPY --from=gobuild /app/goweb /goweb
CMD ["/goweb"]
EXPOSE 8080

CGO_ENABLED : C 구조체 참조 기능 사용할 것인지 확인하는 환경변수


이미지 빌드

docker build -t mygoweb .

이미지로 실행

docker run -d -p 80:8080 mygoweb



Gin : Golang 웹 프레임워크 외부 패키지


패키지 서버에 장애가 생기면 패키지를 다운 받지 못해 어플리케이션 배포 불가
🎈 GO는 공식적인 패키지 서버 두지 않고 GitHub, GitLab, S3 등 인터넷에서 가져옴


작업 디렉토리 : ~/golang/gogin

mkdir ~/golang/gogin
cd ~/golang/gogin
go mod init gogin

gogin.go

package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {     # ping 입력하면
		c.JSON(200, gin.H{
			"message": "pong",                # {"message":"pong"} 출력
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

실행파일 빌드

go build .
or
go run .

관련 파일 확인

go mod tidy
cat go.sum

Dockerfile

FROM golang:1.18-buster AS gobuilder
ENV CGO_ENABLED 0
COPY . /app
WORKDIR /app
RUN go build -o gogin .

FROM scratch
COPY --from=gobuilder /app/gogin /
CMD ["/gogin"]
EXPOSE 8080

이미지 빌드

docker build -t mygogin .

이미지 실행

docker run -d -p 80:8080 mygogin



Node.js


🎈 병렬 처리 특화

Node js -> 16.15.0 LTS 버전 설치 (16.xx)
ubuntu에서 설치


설치

Nodejs 설치 명령어

curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

설치 확인

$ node --version
v16.15.0

시작 가이드

app.js

const http = require('http');  # http : web app 만들 수 있는 라이브러리

const hostname = '127.0.0.1';  # 외부와 연결하려면 '0.0.0.0'
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

Node.js 기본 포트 : 3000

js 파일 실행
( 명령어 : node )

$ node app.js
Server running at http://0.0.0.0:3000/



Dockerizing a Node.js Web app


작업 디렉토리 : ~/node/web

Node.js 앱 만들기
package.json

{
  "name": "docker_web_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "First Last <first.last@example.com>",
  "main": "server.js",                                # 어떤 js 파일을 참조할 것인가
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"                              # express : 노드 js의 웹프레임워크
  }
}

server.js

'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello World');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

패키지 설치 (package.json 파일의 의존성 설치)

npm install

(⚠️정확히 확인해보고 수정하기) 확인

$ ls
node_modules  package-lock.json  package.json  server.js
  • node_modules : Node.js의 패키지가 설치 된 디렉토리
    -> 이미지에 포함 x
  • package-lock.json : 패키지 목록 파일
    -> 이미지에 포함

.dockerignore

mode_modules/
Dockerfile
.dockerignore

Dockerfile

FROM node:16

WORKDIR /usr/src/app
COPY . .
RUN npm install
EXPOSE 8080
CMD ["node","server.js"]

이미지 빌드

docker build -t mynode .

이미지로 실행

docker run -d -p 80:8080 mynode



Docker Hub 이미지 업로드


사용자 인증

명령어로 인증

$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: [본인 username]
Password: [본인 password]
WARNING! Your password will be stored unencrypted in /home/vagrant/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

➕ 이미지는 명령어로만 올릴 수 있음 -> 웹 인터페이스로 올릴 수 x
~/.docker/config.json. -> 여기 패스워드 저장되어있으니 주의

💡현재 도커 호스트를 종료하기 전까지 docker login 상태는 유지되는가??

현재 터미널 유지할 때까지 유효함


이미지 업로드

docker push

$ docker push pyhello:v1-alpine
The push refers to repository [docker.io/library/pyhello]
3251ecc0514a: Preparing
...
denied: requested access to the resource is denied

도커허브 전용 레지스트리(library)에 저장되있는 게 아니라서 오류 발생


이미지 태그

docker tag

$ docker tag pyhello:v1-alpine xxoby/pyhello:v1-alpine

이미지 ID 확인
(동일한 id == 같은 이미지)

$ docker image ls | grep pyhello
pyhello                              v1-alpine            60aba20d0b40   26 hours ago     47.8MB
xxoby/pyhello                        v1-alpine            60aba20d0b40   26 hours ago     47.8MB

본 양식 : docker.io/[내 계정이름]/[이미지:태그]
-> 도커 허브에 올릴 땐 굳이 docker.io를 앞에 붙여줄 필요 x
다른 저장소(GitHub 등)일 땐 붙이기

이미지 업로드 확인

이미지 업로드 시,
Default : Public (Public Repository) 상태

  • 아무나 pull 할 수 있음
    ➕ 무료 계정은 1개의 이미지를 하루에 pull 할 수 있는 횟수 100번으로 제한
  • push는 나만 할 수 있음

Private은 push도 pull도 인증받은 사용자만 가능
➕ 무료 계정은 1번만 무료

🎈 이미지 정보 확인

🎈 사용자가 보는 화면


Repository 생성

🎈 여기선 Private Repository로 구성

Repository로 이미지 push

$ docker tag chello xxoby/xyz
$ docker push xxoby/xyz

➕ Repository > Settings > Private Repository로 전환 / Repository 삭제


이미지 빌드 및 태그 / 푸시

하나의 이미지에 태그 여러 개 붙이는 것 가능

docker build -t xxoby/mygo:latest -t xxoby/mygo:1.0 -t xxoby:/mygo:1 .
docker push xxoby/mygo:latest xxoby/mygo:1.0 xxoby:/mygo:1

docker build -t xxoby/mygo:latest -t xxoby/mygo:1.1 -t xxoby:/mygo:1 .
docker push xxoby/mygo:latest xxoby/mygo:1.1 xxoby:/mygo:1

docker build -t xxoby/mygo:latest -t xxoby/mygo:1.2 -t xxoby:/mygo:1 .
docker push xxoby/mygo:latest xxoby/mygo:1.2 xxoby:/mygo:1

메이저 버전 업그레이드

docker build -t xxoby/mygo:latest -t xxoby/mygo:2.0 -t xxoby:/mygo:2 .
docker push xxoby/mygo:latest xxoby/mygo:2.0 xxoby:/mygo:2

🎈 최종으로 저장되어있는 이미지


➕ Docker Hub 이미지 자동 빌드 기능 (유료)



Docker Compose


🎈Docker의 IaC
Docker Swarm에 컨테이너 오케스트레이션을 위해 Docker를 IaC 형식으로 배포하기 위함
쿠버네티스를 사용하기 때문에 거의 사용할 일 x

현재 3 버전대 사용

명령어

  • docker-compose : 옛날 명령어
  • docker compose : 현재 명령어

예제 1

Compose 파일 생성
-> 서비스 , 네트워크 및 볼륨 등 을 정의 하는 YAML 파일

docker-compose.yaml or docker-compose.yml

version: '3'  # Docker Compose 버전 (3 버전 에서 쓸 수 있는 최신 버전 설치)

services:
  web:   # 컨테이너 이름
    image: httpd   # 컨테이너를 실행하기 위한 이미지 (태그 붙이기 가능)

컨테이너 생성

docker compose up -d
[+] Running 2/2 
 ⠿ Network example1_default  Created    # 작업 디렉토리 이름(example1) : 프로젝트 이름                                                                                 0.2s
 ⠿ Container example1-web-1  Started                                                                                      0.9s

기본적으로 네트워크 를 생성하고 우리가 만들려고 하는 컨테이너 를 생성

옵션

  • up : 아무것도 없는 상태에서 컨테이너 생성
  • run : 있는 컨테이너를 실행시킴

프로젝트 목록 확인

docker compose ls
NAME                STATUS              CONFIG FILES
example1            running(1)          /home/vagrant/compose/example1/docker-compose.yaml

서비스 목록(컨테이너) 확인

 docker compose ps
NAME                COMMAND              SERVICE             STATUS              PORTS
example1-web-1      "httpd-foreground"   web                 running             80/tcp

삭제

docker compose down

💡주의 !!

docker compose down을 하더라도 volume 사라지지 x

  • 삭제 안하면 기존의 volume이 남아있어서 다시 up하면 기존에 생성 되어있던 볼륨 사용함
  • 이전에 잘못 된 설정이 볼륨에 남아서 접속이 안되는 경우 생길 수 있음

해결방법

  • volume prune
  • docker compose down -v : 볼륨도 같이 삭제

예제 2

🌟 가장 일반적인 형식

docker-compose.yaml

version: '3'

services:
  web:
    image: httpd
    restart: always
    ports:
      - 80:80
    environment:
      MSG: hello world
    volumes:      # 서비스를 어떤 볼륨에 연결할 것인가
      - web-contents:/var/www/html
    networks:
      - web-net
  web2:
    image: nginx
    networks:    # 서비스를 어떤 네트워크에 연결할 것인가
      - web-net

volumes:
  web-contents:  # 실제 만들 볼륨 이름 부여

networks:
  web-net:   # 실제 만들 네트워크 이름 부여

컨테이너 실행

docker compose up -d


컨테이너에서 명령어 추가 실행
-> 현재 생성된 컨테이너 bash shell 사용

docker compose exec web bash
# bash shell of the "web" container 
echo $MSG
hello world

apt update
apt install curl
curl web2

curl web2 에서 확인 가능하듯이
🎈 Docker compose 에서 컨테이너는 서로 이름 으로 가리킬 수 있음 (--link 옵션 필요 x)


예제 3

기존 이미지를 사용하여 빌드하거나
도커 파일을 빌드해서 바로 실행 가능

docker-compose.yaml

version: '3'

services:

  myflask:
    build: ./flask 

  mydjango:
    build: ./Django

기존 파일들을 현재 디렉토리로 복사

 cp -r ~/pythontest/flask .
 cp -r ~/pythontest/Django .

컨테이너 실행

docker compose up -d




profile
Be on CLOUD nine! ☁️ ( 수정 예정 == 📌)

0개의 댓글