• Home
  • About
    • Dochoi의 소소한 코딩 모음 photo

      Dochoi의 소소한 코딩 모음

      코딩을 하면서 느낀점들을 모은 공간입니다.

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags
    • AI
    • Algorithm
    • Algorithm-Test
    • Cloud
    • Docker
    • Kubernetes
    • iOS
    • Culture
  • Projects

컨테이너로 애플리케이션 실행하기

08 Jun 2020

Reading time ~6 minutes

docker

컨테이너로 애플리케이션 실행하기

학습 목표

  • 도커의 이미지, 컨테이너, 포트포워딩을 이해하고 HTTP 응답을 반환하는 간단한 애플리케이션을 만든다.
  • 도커 이미지를 만들기 위한 Dockerfile을 작성한다.
  • reference 도커/쿠버네티스를 활용한 컨테이너 개발 실전 입문

목차

  • 컨테이너로 애플리케이션 실행하기
    • 학습 목표
    • 목차
    • 도커이미지와 도커 컨테이너는 무엇인가?
    • 도커 이미지 받아오기
      • FROM
      • RUN
      • COPY
      • ADD
      • CMD
      • ENTRYPONT
    • 그 밖의 DockerFile 인스트럭션
    • 도커 이미지 빌드하기
    • 포트 포워딩
  • reference

도커이미지와 도커 컨테이너는 무엇인가?

개념 역할
이미지 도커 컨테이너를 구성하는 파일 시스템과 실행할 애플리케이션 설정을 하나로 합친것으로, 컨테이너를 생성하는 템플릿 역할을 한다.
컨테이너 도커 이미지를 기반으로 생성되며, 파일 시스템과 애플리케이션이 구체화 돼 실행되는 상태

도커 이미지 받아오기

docker image pull [받아올 이미지]

ex 1)

docker image pull debian:buster

ex2)

docker image gihyodocker/echo:latest

내려받은 이미지를

docker container run

명령으로 실행할 수 있다.

ex)

테스트 시

docker container run -t -p 9000:8080 gihyodocker/echo:latest

이 컨테이너는 옵션을 통해 포트 포워딩이 적용되어 있다. (-p 9000:8080부분, 나중에 다시 나올것이니 일단 넘어가자) 도커 실행환경의 포트 9000을 거쳐 HTTP 요청을 전달받는다.

docker 터미널을 하나 더 띄워 curl명령으로 접근해본다.

curl http://localhost:9000/

책을 그대로 따라했지만 연결이 안된다.

netstat -a

명령어로 포트가 연결 되었는지 확인 해봤으나 연결이 되어있지 않다.

이유는 역시 윈도우에서 가상머신을 띄워서 진행했기 때문이다.

Toolbox에선 default 주소가 localhost가아닌, 192.168.99.100이다.

curl http://192.168.99.100:9000/

로 명령어를 바꾸니 정상 작동 한다.

컨테이너를 만들고 실행하는법에 대한 감을 잡기 위해 Go언어로 간단한 웹 서버를 만들어 보았다.

(책에 있는거 그대로 따라썼다.. Go언어로 프로젝트를 하나 진행해 볼 생각이다.)

package main

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

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		log.Println("received request")
		fmt.Fprintf(w, "Hello Docker!!")
	})

	log.Println("start server")
	server := &http.Server{Addr: ":8080"}
	if err := server.ListenAndServe(); err != nil {
		log.Println(err)
	}

}

간단한 함수설명

  • 모든 HTTP 요청에 대해 Hello Docker !! 라는 응답을 보낸다.
  • 포트 8080로 요청을 받는 서버 애플리케이션으로 동작한다.
  • 클라이언트로부터 요청을 받으면 received request라는 메시지를 표준으로 출력한다.

그리고 DockerFile을 만든다.

FROM golang:1.9

RUN mkdir /echo
COPY main.go /echo

CMD ["go", "run", "/echo/main.go"]

FROM

From 인스트럭션은 도커 이미지의 바탕이 될 베이스 이미지를 지정한다. Dockerfile로 이미지를 빌드할 때 가장 먼저 From 인스트럭션에 지정된 이미지를 내려받는다.

기본적으로 이 이미지는 “DockerHub”라는 레지스트리에서 참조한다.

main.go를 실행하려면 Go 언어의 런타임이 설치된 이미지가 있어야 한다.

이 런타임이 설치된 golang:1.9 이미지를 받아온다.

  • dockerfile에서 image를 pull하는것으로 이해하였다.

RUN

RUN 인스트럭션은 도커 이미지를 실행 할때 컨테이너 안에서 실행할 명령을 정의하는 인스트럭션이다. 인자로 도커 컨테이너 안에서 실행할 명령을 그대로 기술한다. 여기서는 main.go 애플리케이션을 배치하기 위한 /echo 디렉터리를 mkdir 명령으로 만들었다.

COPY

COPY 인스트럭션은 도커가 동작 중인 호스트 머신의 파일이나 디렉터리를 도커 컨테이너 안으로 복사하는 인스트럭션이다.

예제에서는 main.go파일을 컨테이너 안으로 복사하였다. 복사 위치는 RUN으로 만든 /echo 디렉터리이다.

ADD

COPY 인스트럭션과 유사하게 ADD 인스트럭션이 있다. 보통 COPY인스트럭션을 주로 쓴다. 그래도 알아놓자

아래는 COPY 인스트럭션과의 차이점이다.

  • URL을 복사할 source로 사용할 수 있다. remote에 있는 파일을 받아서 복사하게 된다.
  • source 파일이 gzip과 같이 일반적으로 잘 알려진 압축형태인 경우, 압축을 풀어준다.

  • 압축된 remote 파일인 경우, 압축을 풀어주지는 않는다.

CMD

CMD 인스트럭션은 도커 컨테이너를 실행할때 컨테이너 안에서 실행할 프로세스를 지정한다.

즉, RUN 인스트럭션은 이미지를 빌드할때 실행되고, CMD 인스트럭션은 컨테이너를 시작할 때 한번 실행된다. RUN은 애플리케이션 업데이트 및 배치에, CMD는 애플리케이션 자체를 실행하는 명령어라고 생각하면 된다.

go run /echo/main.go

은 CMD 인스트럭션으로 기술하면

CMD ["go", "run", "/echo/main.go"]

이렇게 된다. 명령을 공백으로 나눈 배열로 나타낸다.

CMD go run/echo/main.go

처럼 그대로 작성할 수도 있지만 되도록이면 인자 배열방식을 사용하라고 한다.

구글링을 해보니 인자 배열 방식이 조금 더 단순하게 빌드된다.

CMD에 지정한 명령을 docker container run에서 지정한 인자로 오버라이드 할 수 있다.

즉

CMD["uname"]
$ docker container run $(docker image build -q . ) echo yay

을 하면 uname이아닌 echo yay명령이 실행된다.

인자 표기 방식 동작
CMD [“실행파일,” 인자1”, 인자2] 실행파일에 인자를 전달한다.
사용을 권장하는 방식
CMD 명령 인자1 인자2 명령과 인자를 지정한다. 셸에서 실행되므로
셸에 정의된 변수를 참조할 수 있다.
CMD [“인자1”, “인자2”] ENTRYPOINT에 지정된 명령에 사용된 인자를 전달한다.

ENTRYPONT

ENTRYPOINT 인스트럭션을 사용하면 컨테이너의 명령 실행 방식을 조정할 수 있다.

ENTRYPOINT는 CMD와 마찬가지로 컨테이너 안에서 실행할 프로세스를 지정하는 인스트럭션이다.

ENTRYPOINT를 지정하면 CMD의 인자가 ENTRYPOINT에서 실행하는 파일에 주어진다.

ex)

$ docker container run -it golang:1.10 go version

으로 go version을 실행할 수 있다 하지만

docker file에

FROM golang:1.10



ENTRYPOINT ["go"]

CMD [""]

라 쓰고

docker image build -t ch02/golang:latest .

빌드 하면

docker container run ch02/golang:latest version

으로 go를 쓰지 않아도 된다 이로써 컨테이너를 어느정도 제한 할 수 있다.

하지만 docker container run –entrypoint 옵션으로 오버라이드가 가능하다.

그 밖의 DockerFile 인스트럭션

LABEL - 제작자 이름을 적을 수 있다.

ENV - 도커 컨테이너 내부의 환경변수를 지정한다.

ARG - 이미지를 빌드할때 일시적으로 환경변수를 만들 수 있다.

상세설명 및 모든 명령 - https://docs.docker.com/engine/reference/builder/

도커 이미지 빌드하기

이미지 빌드는

docker image build -t 이미지명[:태그명] Dockerfile의 경로

로 이루어진다.

docker image build 명령은 도커 이미지를 빌드하기 위한 명령이다.

-t 옵션

  • 이미지명을 지정한다. 태그명도 지정할 수 있으며, 생략 시에는 latest 태그가 붙는다.

  • -t옵션과 이미지명은 반드시 지정해야 한다고 생각하는 편이 좋다. -t 옵션 없이도 빌드 자체는 가능하지만, 이미지명 없이는 해시값만으로 이미지를 구별해야하므로 사용하기가 상당히 번거롭다.

docker image build -t dochoi/echo:latest .

이런식으로 이미지명의 충돌을 방지하기 위해 네임스페이스를 추가할수 있다. (dochoi)

SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

윈도우에서는 위와 같은 워닝이 발생한다. 무시하자.

docker image ls

로 생성된 이미지의 정보를 알 수있다.

  • REPOSITORY : 같은 이름을 가졌지만 서로 다른 태그가 달린 이미지의 집합으로, 일반적으로 깃허브 저장소처럼 [소유자명/애플리케이션명]과 같이 이름이 붙는다.

    docker container run
    

    명령으로 컨테이너를 실행할 때 이 Repository를 지정한다.

  • TAG : 특정이미지를 식별하기 위해 사용하는 값이다.

  • IMAGE ID : 이미지를 유일하게 식별하기 위해 사용하는 식별자

이미지를 생성했으니

docker container run example/echo:latest

으로 컨테이너를 실행한다. 이 컨테니너는 계속 포어그라운드에서 동작한다 컨테이너를 종료하려면 Ctrl+C 로 나온다. 백그라운드로 컨테이너를 실행하기위해

-d 옵션을 준다

docker container run -d example/echo:latest

포어그라운드 프로세스

사용자가 입력한 명령이 실행되어 결과가 출력될 때 까지 기다려야 하는 포어그라운드 방식으로 처리되는 프로세스

백그라운드 프로세스

명령을 실행하면 명령의 처리가 끝나는 것과 관계없이 곧바로 프롬프트가 출력되어 사용자가 다른 작업을 할 수 있음

-d 옵션을 붙여 컨테이너를 실행하면 컨테이너의 ID가 출력된다. 이는 유일 식별자이다.

docker container ls

를 실행하면 나오는 CONTAINER ID 칼럼에 나온다 (앞 12자리)

docker container, docker run 과 docker run, docker image pull 은 같다.

하지만 명령의 의도가 드러나는것을 생각해 축약되지 않은 명령을 사용할 것이다.

docker container run -it -p 80:80 -p 443:443 dochoi:fin

채점시

포트 포워딩

Go 언어로 이전의 포트 8080을 리스닝 하는 코드를 작성하였다.

curl http://192.168.99.100:8080/

로 GET 요청을 보내보았다. 연결이 되지 않는다. 왜 그럴까? 도커 컨테이너는 가상환경이지만 외부에서 봤을땐 독립된 하나의 머신이다. 분명 echo 애플리케이션은 8080포트를 리스닝하고 있지만, 이 포트는 컨테이너 안에 한정된 포트이다. curl을 컨테이너 안에서 실행하면 올바른 응답을 받을 수 있다. 하지만 외부에서는 컨테이너 포트를 바로 사용할 수 없다. 이처럼 HTTP 요청을 받는 애플리케이션을 이용하려면 컨테이너 밖에서 온 요청을 컨테이너 안에 있는 애플리케이션에 전달해줘야 한다.

이 역할을 하는것이 포트 포워딩이다.

포트포워딩을 사용하기 전에 앞서 실행한 컨테이너를 정지시킨다.

docker container stop $(docker container ls --filter "ancestor=example/echo" -q)
docker container run -d -p 9000:8080 example/echo:latest

그다음 -p 옵션으로 호스트 포트 9000을 컨테이너포트 8080으로 연결한다.

curl http://192.168.99.100:9000/

그리고 호스트포트 9000에 GET 요청을 보내면 정상적으로 응답이 받아진다.

이로써 도커 이미지 생성, 컨테이너 실행, 포트 포워딩에 대해 이해하였다.

reference

  • 도커/쿠버네티스를 활용한 컨테이너 개발 실전 입문


Docker Share Tweet +1