본문 바로가기
MLOps

도커 기초

by 볼록티 2022. 3. 21.
728x90
반응형

docker desktop


도커 기초를 다시 잡기 위해 인프런 강의를 참고해 필기했다. 기본적으로 도커 명령어와 컨테이너 실행 방법 그리고 이미지를 빌드하는 과정에 대해 공부한다.

Mac OS나 window 운영체체에서는 도커 데스크탑 설치 후에 진행하면 된다!

 

 

참고) 도커 컨테이너 실행 명령어 

$ docker run [OPTION] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...]
-d 백그라운드 모드 실행
-p 호스트와 컨테이너의 포트 연결
-v 호스트와 컨테이너의 디렉토리 연결
-e 컨테이너 내의 환경변수 설정
--name 컨테이너 이름 설정
--rm 프로세스 종료시 컨테이너 자동 제거
-it 터미널 입력을 위한 옵션
--network 네트워크 연결

 

- 우분투 컨테이너 실행

아래의 명령어로 우분투 20.04 버전을 실행시킬 수 있다. 원래 이미지를 다운 받거나 빌드한 이미지가 있어야 run이 되는데, 아래 같은 기본적인 이미지는 이미지가 없어도 도커가 알아서 이미지를 pull 해준다.

$ docker run ubuntu:20.04

컨테이너는 프로세스라 어떤 명령이 주어지지 않아 위의 식으로 진행하면 우분투를 켰다가 끄는 상황이 된다.

 

아래의 명령어로 실행시키면 우분투 환경에서 터미널에 경로 /bin/sh 에 입장하게 된다. 그 안에서 일반적인 터미널 명령어를 작성하면서 우분투 환경에서 터미널을 돌아다닐 수 있다.  -it 옵션을 주어야 우분투 환경에서 돌아다니게 될 수 있다! 컨테이너는 exit 를 쳐서 빠져나오도록 한다. exit하면 실행을 중단하고 컨테이너를 빠져나오는데,  --rm 옵션을 하면 실행을 종료하면 동시에 컨테이너를 삭제한다.

$ docker run --rm -it ubuntu:20.04 /bin/sh

 

- hashicorp 웹서버 컨테이너 실행

-p 5678:5678 은 아래의 컨테이너 hashicorp/http-echo 와 내 로컬 포트 5678이랑 포트를 연결해주라는 의미이다. 아래의 명령어를 실행하면 인터넷창 하나 켜서 localhost:5678 하면 텍스트 "hello world"가 출력되어 있음을 확인할 수 있다.

$ docker run --rm -p 5678:5678 hashicorp/http-echo -text="hello world"

 

curl은 브라우저의 http 접속 결과를 받아오는 명령어이다. 터미널을 하나 더 켜서 아래의 코드를 쳐서 위의 코드 결과를 받아볼 수 있다.

$ curl loaclhost:5678

 

- redis 데이터베이스 컨테이너 실행

redis 데이터베이스 이미지를 다운 및 실행시키는 코드는 아래와 같다.

$ docker run --rm -p 1234:6379 redis

 

 

 

-p 옵션에서 포트연결은 "호스트(나)포트:컨테이너포트" 이기 때문에 호스트(나) 포트는 사용자가 설정할 수 있다. 

 

- MySQL 컨테이너 실행

MySQL 컨테이너를 실행해본다. -d 옵션으로 백그라운드에서 실행하게 된다. cmd 에서는 역슬래쉬 대신에 ^ 를 사용한다.

$ docker run -d -p 3306:3306 \
   -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
   --name mysql \
   mysql:5.7

아래의 명령어는 mysql을 실행하는 명령어이다. 앞쪽의 mysql은 컨테이너 이름이다
docker 명령어 이후는 mysql라는 이름의 컨테이너로 mysql에 접속하고 난 다음에 실행할 명령어이다.

exec 명령어로 컨테이너 내부에 접속해 활동을 할 수 있다. ssh server는 보안상의 이유로 추천하지 않고, exec 명령어를 사용한다.

$ docker exec -it mysql mysql

# mysql 진입 후
  create database wp CHARACTER SET utf8;
  grant all privileges on wp.* to wp@'%' identified by 'wp';
  flush privileges;
  quit

 

- WORDPRESS 블로그 실행

위의 mysql을 실행한 상태에서 생성한다. wordpress 블로그를 실행하는 방법은 아래와 같다. 아래의 코드를 치면 이미지가 없으면 다운로드를 받고 실행하게 된다. 

$ docker run -d -p 8080:80 \
  -e WORDPRESS_DB_HOST=host.docker.internal \  #띄워놓은 ip로 접속함.
  -e WORDPRESS_DB_NAME=wp \
  -e WORDPRESS_DB_USER=wp \
  -e WORDPRESS_DB_PASSWORD=wp \
  wordpress

 

 

 

참고) 도커 이미지관련 명령어

docker rmi 이미지 삭제
docker pull 이미지 불러오기
docker logs 컨테이너 로그 확인
-f: 실시간 로그 확인
docker images 이미지 확인

 

 

 

- 네트워크 연결

 앞서 mysql데이터베이스와 워드프레스를 연결할 때 이름 없이  host.internal이라는 가상의 이름으로 사용했는데, 이름을 지정해서 도커 컨테이너끼리 이름으로 통신할 수 있는 가상 네트워크를 만든다.

 아래의 명령어로 가상 네트워크를 만드는 형식이다.

$ docker network create [OPTIONS] NETWORK

app-network라는 이름으로 앞서 mysql과 wordpress가 통신할 네트워크를 생성한다.

$ docker network create app-network

아래의 명령어로 기존에 존재하는 컨테이너에 네트워크를 추가한다.

$ docker network connect app-network mysql

 

기존의 워드프레스 컨테이너를 삭제한 후, 아래의 명령어로 다시 워드프레스 컨테이너를 생성한다. 

$ docker run -d -p 8080:80 \
  --network=app-network \ # 네트워크를 app-network에 연결함
  -e WORDPRESS_DB_HOST=mysql \ # mysql에 이름으로 접근
  -e WORDPRESS_DB_NAME=wp \
  -e WORDPRESS_DB_USER=wp \
  -e WORDPRESS_DB_PASSWORD=wp \
  wordpress

 

- volume mount(-v) 명령어

아래의 명령어는 mysql컨테이너를 중단한 후 mysql컨테이너를 삭제한다. 이후 다시 network와 이름을 지어 mysql:5.7 이미지를 통한 컨테이너를 실행한다. 

$ docker stop mysql
$ docker rm mysql
$ docker run -d -p 3306:3306 \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
  --network=app-network \
  --name mysql \
  mysql:5.7

위의 명령어를 실행하면 기존의 워드프레스 localhost:8080에 접속하면 모든 데이터베이스 연결이 끊어졌다는 에러를 볼 수 있게 된다.

이는 워드프레스가 mysql에 데이터베이스를 저장하면서 운영되고 있었는데, 가상 컨테이너가 사라지면서 워드프레스에 표현되었던 모든 데이터가 날아가서 그렇다.

 

이를 방지하기 위해 로컬과 연결을 짓어주는 것이 volume mount의 역할이다.
 -v C:\Users\USER\mysql:/var/lib/mysql 명령어를 추가해주었는데, 내로컬경로 : 가상환경mysql컨테이너의 경로 라고 보면 된다.

$ docker stop mysql
$ docker rm mysql
$ docker run -d -p 3306:3306 \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
  --network=app-network \
  --name mysql \
  -v C:\Users\USER\mysql:/var/lib/mysql \
  mysql:5.7

위의 코드를 실행하면 빈 데이터베이스라서 mysql 컨테이너에 접속해서 다시 워드프레스 관련 데이터베이스를 생성해준다. 그리고 로컬호스트 8080에 다시 들어가서 다시 데이터를 입력해본다.

$ docker exec -it mysql mysql

# mysql 진입 후
 create database wp CHARACTER SET utf8;
 grant all privileges on wp.* to wp@'%' identified by 'wp';
 flush privileges;
 quit

 그리고 나와서 로컬호스트에서 만들어놨던 내로컬경로에 들어가 확인해본다.

이제 mysql 컨테이너를 삭제해본다.

docker stop mysql 하면 웹에서 localhost:8080은 접속이 불가능하다고 나온다. 

이 때 위에서 작성해보았던 -v 옵션이 추가된 코드를 아래와 같이 쳐본다.

$ docker stop mysql
$ docker rm mysql
$ docker run -d -p 3306:3306 \
  -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
  --network=app-network \
  --name mysql \
  -v C:\Users\USER\mysql:/var/lib/mysql \
  mysql:5.7

그리고 다시 localhost:8080 에 접속하면, 내가 수정했었던 데이터가 내로컬경로로부터 그대로 들여와진걸 확인할 수 있다.

-v 옵션으로 컨테이너가 종료되도 데이터를 보존할 수 있다는 기능을 염두에 두자!

 

- docker-compose

docker 문법에 비해 훨씬 편리하게 이미지를 빌드하고 컨테이너를 운영한다.

아래의 docker-compose.yml 파일로 mysql과 wordpress를 docker-compose로 실행한다. yml파일은 띄어쓰기를 기준으로 만드는 형식이다.

 만약 윈도우 cmd 라면 vim를 다운해두자. https://www.vim.org/download.php

$ mkdir wp
$ cd wp

$ vim docker-compose.yml

docker-compose.yml을 만들었으면 아래와 같이 docker-compose.yml파일을 채워두자.

version: '2'
services:  #실행할 컨테이너들
  
  db: #컨테이너 이름
    image: mysql:5.7 #컨테이너에 사용할 이미지 이름
    volumes: #마운트 경로 설정.볼륨
      - .\mysql:/var/lib/mysql
    restart: always #컨테이너가 죽으면 자동으로 재시작 옵션: "no", on-failure, unless-stopped
      environment: #-e 옵션. 환경변수 설정.
        MYSQL_ROOT_PASSWORD: wordpress
        MYSQL_DATABASE: wordpress
        MYSQL_USER: wordpress
        MYSQL_PASSWORD: wordpress
   
   wordpress:
     image: wordpress:latest
     volumes:
       - ./wp:/var/www/html
     ports:
       - "8000:80" #포트. [호스트]:[컨테이너포트]
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_PASSWORD: wordpress

기존의 mysql과 wordpress 컨테이너를 중지하고, 삭제해준다!

 

docker-compose up 을 실행한다. 백그라운드 실행 옵션은 -d

혹시 아래와 같은 에러가 난다면, 들여쓰기나 형식에 문제가 있으니 꼼꼼히 코드를 체크해준다.

ERROR: yaml.scanner.ScannerError: mapping values are not allowed here   in ".\docker-compose.yml", line 5, column 14

처음 실행하면 오래걸림.! 마운트는 현재 경로에 각각 mysql, wp 폴더와 연동하게함.

docker-compose down으로 컨테이너를 종료할 수 있다.

 

 

- docker images 만들기 

 

우분투 최신버전 이미지를 사용한 컨테이너를 만들고 그안에 깃을 설치해본다. 그러면 git이 설치된 우분투 컨테이너를 가질 수 있다.

$ docker run --rm ubuntu #우분투 최신버전 확인 및 설치
$ docker run -it ubuntu:latest bash #우분투 최신버전 컨테이너 실행과 바로 bash 실행

우분투에 진입했다면 아래의 명령어로 git을 설치한다.

$ apt-get update
$ apt-get install -y git

$ git version #git version확인

 

이제 설치된 git으로 커밋을 한다.

git이라는 컨테이너에 우분투의 태그가 git인 것으로 커밋한다.

$ docker commit git ubuntu:git

그러면 레포지토리가 ubuntu이고 TAG가 git인게 생성된다. 

 이번엔 태그가 git인 ubuntu를 git2라는 컨테이너 이름으로 다시 생성해본다. 그러면 git이 이미 설치된 ubuntu:git 이미지를 컨테이너 이름이 git2라는 컨테이너를 실행하게 된다. 컨테이너 git2의 bash에서 git version을 쳐보면 이미 git이 설치돼 있음을 알 수 있다.

$ docker run -it --name git2 ubuntu:git bash

 git이라는 태그가 달린 ubuntu:git는 기존의 베이스 이미지였던, ubuntu:latest와 달리 git이 설치된 이미지가 되는 것이다. base image가 아니라 custom image 가 된 것이다.

 

참고) 도커 이미지를 만드는 명령어의 규칙

 앞선에는 commit이라는 명령어로 ubuntu:git 이라는 이미지를 만들었고, 아래와 같이 build 명령어로 만들 수 있다.
docker build -t name_space/ubuntu:git .

-t는 태그를 만들겠다는 옵션, name_space는 사용자 아이디(없는경우 디폴트로 적용됨), ubuntu는 이미지 이름, git은 태그, .은 빌드 컨텍스트(빼먹으면안됨.)

 

TDD : Test Driven Development의 약자로 '테스트 주도 개발'이라고 한다. 반복 테스트를 이용한 소프트웨어 방법론으로 작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 구현한다."
----> 이미지 빌드에 TDD를 염두에 두고 근성있게 개발하자는 조언.!

 

- 도커 파일을 만들어서 이미지를 빌드하는 방법

확장자가 없는 그냥 dockerfile을 하나 만든다.

 

Dockerfile을 구성하는 명령어는 아래와 같다.

 FROM 기본이미지
RUN 쉘 명령어 실행
CMD 컨테이너 기본 실행 명령어(Entrypoint의 인자로 사용)
EXPOSE 오픈되는 포트 정보
ENV 환경변수 설정
ADD 파일, 디렉토리 추가. URL/ZIP 사용가능
COPY 파일, 디렉토리 추가
ENTRYPOINT 컨테이너 기본 실행 명령어
VOLUME 외부 마운트 포인트 생성
USER RUN, CMD, ENTRYPOINT를 실행하는 사용자
WORKDIR 작업 디렉토리 설정
ARGS 빌드타임 환경변수 설정
LABEL key - value 데이터
ONBUILD 다른 빌드의 베이스로 사용될때 사용하는 명령어

 

아래는 Dockerfile 안에 담긴 텍스트이다.

FROM ubuntu:latest #기본 베이스 이미지

RUN apt-get update #RUN: 실제 이미지 안에서 실행하는 작업 명령어
RUN apt-get install -y git

 

아래의 명령어로 Dockerfile을 이용해서 이미지를 빌드해보자! (위 Dockerfile은 같은 경로에 있어야함._)

$ docker build -t ubuntu:git-dockerfile .

Dockerfile로 빌드한 이미지로 git3라는 이름의 컨테이너를 만들어보자. 그리고 깃버전을 확인해보면 깃이 설치된 우분투환경임을 확인할 수 있다.

$ docker run -it --name git3 ubuntu:git-dockerfile bash

 

Dockerfile로 빌드하면 이미지를 어떻게 빌드하는지를 기록으로 남겨있다는 것이 재설치, 업데이트 할 때 용이하다.

 

 

 

- 도커 이미지 만들기 - 웹 애플리케이션

https://www.fastify.io/docs/latest/Guides/Getting-Started/ 공식 홈페이지에서 npm을 사용하니 먼저, npm을 설치해준다. 

 

 현재 디렉토리에서 초기화를 해준다. 엔터 계속치면 초기화가 된다.

$ npm init

 공식홈페이지에서 명시한대로 그리고 패키지를 설치해준다.

$ npm i fastify --save

그리고 app.js 파일을 하나 만든다. 아래처럼 내용을 입력해준다.

// Require the framework and instantiate it
const fastify = require('fastify')({
 logger: true
})
// Declare a route
fastify.get('/', function (request, reply) {
 reply.send({ hello: 'world' })
})
// Run the server!
fastify.listen(3000, '0.0.0.0', function (err, address) {
 if (err) {
 fastify.log.error(err)
 process.exit(1)
 }
 fastify.log.info(`server listening on ${address}`)
})

 

아래의 명령어를 실행하여 localhost:3000 에 hello world가 출력되는지 확인한다.

$ node app.js

# 다른 CLI를 열고, 아래의 명령어로 확인한다.

$ curl localhost:3000

 

이제 도커파일로 앱을 실행시켜보자.

Dockerfile은 아래와 같다.

# 1. node 설치
FROM ubuntu:20.04
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs npm


# 2. 소스 복사
COPY . /usr/src/app #현재경로의 모든 파일을 /user/src/app에 모두 복사

# 3. Nodejs 패키지 설치
WORKDIR /usr/src/app #현재경로 지정
RUN npm install #지정 경로에서 실행

# 4. WEB 서버 실행 (Listen 포트 정의)
EXPOSE 3000
CMD node app.js #컨테이너 기본 실행 명령어

 

현재 경로에는 아래와 같은 파일들이 존재하고 있는데(웹패키지 설치부터 생성된 파일들) node_modules는 제외시킬 필요가 있어서, 이를 위한 파일을 만든다.

파일이름은 .dockerignore 이다. 아래의 한 문장을 넣어준다.

node_modules/*

 

만든 Dockerfile로 이미지를 빌드해보자. web이라는 이름의 이미지로 빌드한다.

docker build -t web .

이미지 빌드는 시간이 오래걸린다. 

 

 

그래서 최적화를 하는 방법들이 있다.

 

# 1. node 설치
FROM node:12
### 줄일 수 있는 이유는 설치가 모두 된 이미지 node:12가 이미 존재했을 경우이다.


# 1.5 패키지 우선 복사
COPY ./package* /usr/src/app/
WORKDIR /usr/src/app
RUN npm install

# 2. 소스 복사
COPY . /usr/src/app #현재경로의 모든 파일을 /user/src/app에 모두 복사
### 위의 COPY를 진행할 때 /user/src/app에 파일들의 변화가 없다면 기존 캐시를 사용하여 빠르게 넘어감.

# 3. Nodejs 패키지 설치
WORKDIR /usr/src/app 
### 위의 소스 복사에서 파일이 몇개 변경되었다고 RUN npm install를 전부 다시 진행하는 비효율이 
있다. 그래서 소스 복사 이전에 캐시를 확인하고 설치되어있으면 캐시를 사용함.

# 4. WEB 서버 실행 (Listen 포트 정의)
EXPOSE 3000
CMD node app.js #컨테이너 기본 실행 명령어

FROM node:12 를 FROM nede:12-alpine 를 입력한다. 사용하지 않는 파일을 모두 제외한 이미지이다. 그러면 이미지의 용량이 대폭 감소된다.

 

 

 

728x90
반응형

'MLOps' 카테고리의 다른 글

딥러닝 모델 컨테이너 띄우기(wt. GPU)  (0) 2022.03.31
nvidia-docker 설치 및 컨테이너 띄우기 with GPU  (0) 2022.03.31
GPU 사용 환경 세팅  (0) 2022.03.26
MLOps를 위한 잡동사니  (0) 2022.03.26
우분투에 도커 설치  (0) 2021.08.31

댓글