無知

갈 길이 먼 공부 일기

기술 공부/쿠버네티스

쿠버네티스 (1-2) | 도커 파일 명령어 정리

moozii 2022. 1. 18. 22:14
# Alpine 3.7 버전 golang 1.10.1 이미지를 사용
FROM golang:1.10.1-alpine3.7

# 8080 포트 오픈
EXPOSE 8080

# 빌드할 머신에 있는 main.go 파일을 컨테이너에 복사
COPY ./main.go ./

# 컨테이너 내부에서 명령어 실행
RUN go build -o ./go-app ./main.go

# 실행 계정을 nobody로 변경
USER nobody

# 컨테이너가 기동할 때 실행할 명령어 정의
ENTRYPOINT ["./go-app"]
 

GitHub - MasayaAoyama/kubernetes-perfect-guide: 『Kubernetes完全ガイド』の付録マニフェストのリポジトリ / "

『Kubernetes完全ガイド』の付録マニフェストのリポジトリ / "Kubernetes perfect guide" sample manifest repository - GitHub - MasayaAoyama/kubernetes-perfect-guide: 『Kubernetes完全ガイド』の付録マニフェストのリポジト

github.com

 

아래의 명령어 정리는 다음 참고자료들을 인용했습니다.
보다 깊이 공부하시고자 하는 분들은 아래 참고자료 중 하나를 골라 공부해보세요!

https://ghwlchlaks.github.io/dockerfile-instruction
https://wonit.tistory.com/345
http://pyrasis.com/book/DockerForTheReallyImpatient/Chapter07/03
https://youngmind.tistory.com/entry/Docker-%EA%B0%95%EC%A2%8C-4-%EB%8F%84%EC%BB%A4%EC%9D%B4%EB%AF%B8%EC%A7%802-Dockerfile-%EA%B8%B0%EB%B0%98-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%A7%8C%EB%93%A4%EA%B8%B0
https://cultivo-hy.github.io/docker/image/usage/2019/03/14/Docker%EC%A0%95%EB%A6%AC/
https://www.daleseo.com/dockerfile/
https://bluese05.tistory.com/53

 

https://ddok2.github.io/2018/01/12/docker-command/

 

 

  • FROM
    • 기반 이미지를 지정합니다.
    • FROM 명령문은 이 base 이미지를 지정해주기 위해서 사용되는데, 보통 Dockerfile 내에서 최상단에 위치합니다. base 이미지는 일반적으로 Docker Hub와 같은 Docker repository에 올려놓은 잘 알려진 공개 이미지인 경우가 많습니다.
    • FROM 명령어는 사용할 이미지를 지정하는 명령어입니다. ubuntu, node와같은 이미지파일을 지정합니다. 지정할때는 :뒤에 특정 버전을 지정하여 사용할 수 있습니다.
      • FROM golang:1.10.1-alpine3.7
  • MAINTAINER
    • 컨테이너 이미지 관리자 정보를 기입합니다. (현재는 잘 사용하지 않습니다. LABEL을 사용합니다.)
    • ​Dockerfile을 관리하는 사람의 이름 또는 이메일 정보를 적습니다. 빌드에 딱히 영향을 주지는 않습니다.
    • 공식 도커 설명서에 따르면 MAINTAINER 는 더 이상 사용하지 않는다고 한다.
  • LABEL
    • 컨테이너 이미지의 메타 데이터를 키 : 밸류 형식으로 지정합니다.
    • LABEL은 MAINTAINER과 같이 이미지에 METADATA를 추가해주는데, Key - Value 로 이루어진다. 이런 특성 덕분에 MAINTAINER 를 LABEL 내부의 key로 구분해서 사용하는게 늘어나게 되었고, 이제 더 이상 MAINTAINER가 쓰이지 않게된 이유이다.
    • LABEL 명령어는 이미지에 라벨을 다는 것입니다.
      • LABEL "abcd@gmail.com"
      • LABEL email="dhslrl321@gmial.com"
      • LABEL version="1.0"
  • USER
    • 명령어를 실행할 계정을 지정합니다.
    • USER 명령어는 해당 docker 이미지를 실행할 user를 지정하는 명령어입니다.
      • USER user
      • USER [uid]:[gid]
  • WORKDIR
    • 명령어를 실행할 작업 디렉토리를 지정합니다. (디렉토리가 없을 경우 생성합니다.)
    • ​RUN, CMD, ADD, COPY등이 이루어질 기본 디렉토리를 설정합니다. 각 명령어의 현재 디렉토리는 한 줄마다​ 초기화되기 때문에 RUN cd /path를 하더라도 다음 명령어에선 위치가 초기화 됩니다. 같은 디렉토리에서​ 계속 작업하기 위해서 WORKDIR을 사용합니다
    • WORKDIR 명령어는 cd의 명령어와 비슷합니다. RUN과 CMD과 같은 명령어가 실행될 이미지 내부에 위치를 지정해주는 명령어입니다.
      • WORKDIR /app/
  • EXPOSE
    • 컨테이너 실행 시 Listen할 포트를 지정합니다
      • Listen이란? 추가 설명은 다음을 확인하세요
        더보기
        더보기
        네트워크(소켓 네트워크 프로그램)에서의 listen의 일반적인 문맥을 알아보기 위해 다음 자료를 가져와봤습니다.
        클라이언트 요청에 대한 처리가 끝나기 전에 새로운 클라이언트가 요청하는 상황이 온다면, 해당 요청을 잠시동안 대기시키기 위한 대기열을 만들 필요가 있다. 이 대기열을 생성하기 위해 listen 함수가 쓰인다. 
    • 도커 컨테이너가 실행되었을 때 요청을 기다리고 있는(Listen) 포트를 지정합니다. 여러개의 포트를 지정할 수​ 있습니다.
    • EXPOSE 명령문은 네트워크 상에서 컨테이너로 들어오는 트래픽(traffic)을 리스닝(listening)하는 포트와 프로토콜를 지정하기 위해서 사용됩니다. 프로토콜은 TCP와 UDP 중 선택할 수 있는데 지정하지 않으면 TCP가 기본값으로 사용됩니다. 여기서 주의할 점은 EXPOSE 명령문으로 지정된 포트는 해당 컨테이너의 내부에서만 유효하며, 호스트(host) 컴퓨터에서는 이 포트를 바로 접근을 할 수 있는 것은 아니라는 겁니다. 호스트 컴퓨터로부터 해당 포트로의 접근을 허용하려면, docker run 커맨드를 -p 옵션을 통해 호스트 컴퓨터의 특정 포트를 포워딩(forwarding)시켜줘야 합니다.
    • 8080 포트에 대한 추가 설명은 다음을 확인하세요
      더보기
      더보기
      8080 포트에 대해 알아보기 : 먼저 포트가 뭔지 알아보자. 인터넷 주소는 IP 이다. 123.123.123.123 과 같은 32비트 숫자이다. 한개의 호스트, 즉 아이피를 가지고 있는 컴퓨터(또는 서버)에서 여러가지 인터넷 서비스를 할 수 있다. 대표적으로 인터넷웹 서비스, 메일 서비스, DNS 서비스, FTP 서비스 등이 있다. 한개의 호스트로 오는 패킷이 어떤 서비스에 대한 요청인지 파악하기 위해서 포트번호라는 것을 사용한다. 가령 인터넷 웹 서비스, 즉 HTTP 서버는 80 포트를 이용한다. 메일서비스, 즉 SMTP 서버는 25번을 사용한다. DNS 서버는 52번, FTP는 21번(passive port는 별도) 을 사용한다. 아래 링크에 더 자세한 port 번호 별 서비스가 지정되어 있다. https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt IANA가 지정한 것인데, 사실 이렇게 하자라고 권유한 것이지 꼭 포트번호를 맞추어서 할 필요는 없다. 한개의 호스트에서 두개 이상의 웹 사이트를 운영하고 싶을 때에 두가지 방법이 있다. (중략) 2. 다른 포트로 서비스 이용하기 : 이 방법은 성격이 다른 서비스를 운영하고 싶을 때에 좋다. 80포트를 사용하는 웹서버 말고, 또 하나의 웹서버를 설치한다. 웹사이트의 특성에 따라 서버의 종류와 특성이 다를 수 있기 때문에 아예 서비스하는 데몬자체가 달라야 할 필요가 있을때이다. 다른 포트로 서비스를 할때에 주로 쓰는 번호가 8080 이다. 8080 포트는 IANA 에서 HTTP Alternate (see port 80) 라고 정의하고 있다.
      (출처 : http://egloos.zum.com/canddi/v/456721)
      • # 8080 포트 오픈
        EXPOSE 8080
    • COPY
      • 로컬에 있는 파일을 컨테이너로 복사한다
      • ​파일이나 디렉토리를 이미지로 복사합니다. 일반적으로 소스를 복사하는 데 사용합니다.​ target 디렉토리가 없다면 자동으로 생성합니다. 
      • COPY 명령문은 호스트 컴퓨터에 있는 디렉터리나 파일을 Docker 이미지의 파일 시스템으로 복사하기 위해서 사용됩니다. 절대 경로와 상대 경로를 모두 지원하며, 상대 경로를 사용할 때는 이 전에 등장하는 WORKDIR 명령문으로 작업 디렉터리를 어디로 전환을 해놨는지 고려해야 합니다.
        • # 빌드할 머신에 있는 main.go 파일을 컨테이너에 복사
          COPY ./main.go ./
        • COPY <src>... <dest>
          COPY ["<src>",... "<dest>"]
          • COPY package.json package.json
    •  ADD
      • 로컬에 있는 tar.gz 파일의 압축을 풀고 파일을 컨테이너로 복사한다
      • ADD 명령어는 빌드 중 호스트의 디렉토리에서 파일을 가져와서 이미지에 파일을 더하는 것입니다. 주의할점은 빌드되는 디렉토리 밖에 위치하는 파일들은 가져오지 않습니다. (양식 : ADD 호스트파일위치 이미지파일위치)
      • ​COPY명령어와 매우 유사하나 몇가지 추가 기능이 있습니다. src에 파일 대신 URL을 입력할 수 있고​ src에 압축 파일을 입력하는 경우 자동으로 압축을 해제하면서 복사됩니다.
      • ADD 명령문은 좀 더 파워풀한 COPY 명령문이라고 생각할 수 있습니다. ADD 명령문은 일반 파일 뿐만 아니라 압축 파일이나 네트워크 상의 파일도 사용할 수 있습니다. 이렇게 특수한 파일을 다루는 게 아니라면 COPY 명령문을 사용하는 것이 권장됩니다.
    • RUN
      • 컨테이너 안에서 명령어를 실행한다
      • ​가장 많이 사용하는 구문입니다. 명령어를 그대로 실행합니다. 내부적으로 /bin/sh -c 뒤에 명령어를​ 실행하는 방식입니다.
      • RUN 명령문은 마치 쉘(shell)에서 커맨드를 실행하는 것 처럼 이미지 빌드 과정에서 필요한 커맨드를 실행하기 위해서 사용됩니다. 쉘(shell)을 통해 거의 못하는 작업이 없는 것 처럼 RUN 명령문으로 할 수 있는 작업은 무궁무진하지만 보통 이미지 안에 특정 소트트웨어를 설치하기 위해서 많이 사용됩니다.
        • # 컨테이너 내부에서 명령어 실행
          RUN go build -o ./go-app ./main.go
        • # npm 패키지 설치
          RUN npm install --silent
    • ENTRYPOINT
      • 컨테이너 가동 시에 실행할 명령어를 정의한다
      • ENTRYPOINT 명령문은 이미지를 컨테이너로 띄울 때 항상 실행되야 하는 커맨드를 지정할 때 사용합니다. ENTRYPOINT 명령문은 Docker 이미지를 마치 하나의 실행 파일처럼 사용할 때 유용합니다. 왜냐하면 컨테이너가 뜰 때 ENTRYPOINT 명령문으로 지정된 커맨드가 실행되고, 이 커맨드로 실행된 프로세스가 죽을 때, 컨테이너로 따라서 종료되기 때문입니다.
      • ENTRYPOINT는 오버라이드 될 수 없다는 특성을 가지고 있습니다. ENTRYPOINT로 정의하는 이유는, 앱의 시작을 고정시키겠다는 의미, 이미지의 목적을 지정하는 것이기 때문에, CMD보다는 컨테이너 가동 시 <반드시 실행해야 하는 커맨드>에 더 적합합니다! CMD의 경우에는, 오버라이드가 가능해, 깔린 어떤 앱이든 실행이 가능하므로, 컨테이너가 의도치 않게 동작할 우려가 있습니다.
        • # 컨테이너가 기동할 때 실행할 명령어 정의
          ENTRYPOINT ["./go-app"]
        • # npm start 스크립트 실행
          ENTRYPOINT ["npm", "start"]
    • CMD
      • 컨테이너 가동 시에 실행할 명령어를 인수한다
      • CMD 명령문은 해당 이미지를 컨테이너로 띄울 때 디폴트로 실행할 커맨드나, ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용합니다. CMD 명령문은 많은 경우, ENTRYPOINT 명령문과 함께 사용하게 되는데, ENTRYPOINT 명령문으로는 커맨드를 지정하고, CMD 명령문으로 디폴트 파리미터를 지정해주면 매우 유연하게 이미지를 실행할 수 있게 됩니다. (아주 간단히 설명하면 $ENTRYPOINT $CMD 꼴이라 생각할 수 있다)
      • CMD 명령문과 RUN 명령문이 햇갈릴 수가 있는데, RUN 명령문은 이미지 빌드 시 항상 실행되며, 한 Dockerfile에 여러 개의 RUN 명령문을 선언할 수 있습니다. 반면에, CMD 명령문은 이미지를 continaer로 띄울 때 딱 한 번 실행 기회를 가지게 되며, 이 기회마저도 docker run 커맨드에 인자를 넘길 경우 상실하게 됩니다.
      • ​도커 컨테이너가 실행되었을 때 실행되는 명령어를 정의합니다. 빌드할 때는 실행되지 않으며 여러 개의 CMD가​ 존재할 경우 가장 마지막 CMD만 실행됩니다. 한꺼번에 여러 개의 프로그램을 실행하고 싶은 경우에는 run.sh​ 파일을 작성하여 데몬으로 실행하거나 supervisord, forego와 같은 여러 개의 프로그램을 실행하는 프로그램을​ 사용합니다. 
        • # ​node 커맨드로 디폴트로는 index.js를 실행하되, docker run 커맨드에 인자가 있는 경우, 해당 인자를 실행하고 싶은 경우, 다음과 같이 Dockerfile을 작성합니다.
          ENTRYPOINT ["node"]
          CMD ["index.js"]
    • ENV
      • ENV 명령어는 환경변수를 지정하는 것으로 파일내부에서 변수처럼 활용이 가능합니다. 
      • 컨테이너에서 사용할 환경변수를 지정합니다. 컨테이너를 실행할 때 -e옵션을 사용하면 기존 값을 오버라이딩​ 하게 됩니다.
      • ENV 명령문은 환경 변수를 설정하기 위해서 사용합니다. ENV 명령문으로 설정된 환경 변수는 이미지 빌드 시에도 사용됨은 물론이고, 해당 컨테이너에서 돌아가는 애플리케이션도 접근할 수 있습니다.
        • # NODE_ENV 환경 변수를 production으로 설정
          ENV NODE_ENV production
        • ENV test 123
          CMD echo $test
          해당 도커파일을 빌드하여 실행하면 test변수의 값인 123이 출력되는 것을 확인 할 수 있습니다. 
    • ARG
      • ARG 명령어는 도커파일 빌드시에 설정하는 옵션들을 지정할 수 있는 명령어 입니다.
      • ARG 명령문은 docker build 커맨드로 이미지를 빌드 시, --build-arg 옵션을 통해 넘길 수 있는 인자를 정의하기 위해 사용합니다.
        • # 예를 들어, Dockerfile에 다음과 같이 ARG 명령문으로 port를 인자로 선언해주면,
          ARG port
          # 다음과 같이 docker build 커맨드에 --build-arg 옵션에 port 값을 넘길 수가 있습니다.
          $ docker build --build-arg port=8080 .
          # 인자의 디폴트값을 지정해주면, --build-arg 옵션으로 해당 인자가 넘어오지 않았을 때 사용됩니다.
          ARG port=8080
          # 설정된 인자 값은 다음과 같이 ${인자명} 형태로 읽어서 사용할 수 있습니다.
          CMD start.sh -h 127.0.0.1 -p ${port}
        • # 아래와 같이 지정할 경우 도커파일 빌드시 arg1 인자를 입력받아야합니다.
          # 또한 arg2의 default값은 value값으로 지정되어 빌드됩니다.
          ARG arg1
          ARG arg2=value

 

<도커 파일 만들 때 주의사항>

도커 파일은, 이미지 경량화와 연관되어 2가지를 고민해야한다.

변경된 이미지를 얼마나 빠르게 배포 가능한가 [경량화]

 

1. 최대한 합칠 수 있는 커맨드는 합치자

변경된 소스를 변경된 부분만 적용하도록 해야 한다.
각각 도커파일의 커맨드 라인 단위로 이미지가 생성된다. 

결국은 나의 한 커맨드는 하나의 이미지 레이어가 된다.

경량화하려면 이미지 레이어를 줄여야 한다.

커맨드 작성 시 COPY나 ADD나 RUN 등 합칠 수 있는 커맨드는 명령어가 길어져도 하나로 합치는 것이 중요하다.

2. 얼마나 자주 바뀌는 커맨드인지 알아봐야
FROM 절은 거의 안바뀌지만, 실제 빌드 시의 dependency package를 먼저 빌드한 뒤 소스를 빌드하는데, 

패키지 설치 전에 나의 소스를 먼저 빌드하도록 순서를 작성하면, 
패키지도 매번 소스 변경마다 계속 재설치가 되어 느리게 된다. 
즉 잘 바뀌는 것들을 하부로 내려서 커맨드 우선순위를 지정해야 한다.

 

 

[추가 참고자료]

 

Dockerfile Entrypoint 와 CMD의 올바른 사용 방법

ENTRYPOINT 와 CMD 는 무엇인가  ENTRYPOINT 와 CMD는 해당 컨테이너가 수행하게 될 실행 명령을 정의하는 선언문이다.  즉, 컨테이너가 무슨 일을 하는지 결정하는 최종 단계를 정의하는 명령이라고 생

bluese05.tistory.com