본문 바로가기
AWS Cloud School 8기/도커(docker)

도커이미지(Docker Image)/ FROM/ WORKDIR/ COPY/ RUN/ CMD/ EXPOSE/ ENV/ Dockerfile

by YUNZEE 2025. 3. 19.
728x90

📌 도커 이미지란?

- Docker 이미지는 애플리케이션과 그 실행에 필요한 모든 파일, 라이브러리, 환경 설정, 종속성 등을 포함한 읽기 전용 템플릿을 말함.

- 이 이미지는 컨테이너를 실행하기 위한 청사진 역할을 하며, 여러 번 재사용할 수 있음.

- 도커 이미지는 계층 구조로 구성되어 있으며, 각각의 계층은 하나의 파일 시스템 변경 사항을 나타냄.

 

Dockerfile - 도커이미지를 만들기 위한 명세포

명세표 - 주문하는 사람의 바람이 담겨있음

실습

FROM: 베이스이미지를 지정

-> 맨 위에 써줘야 함

FROM nginx:latest

- 베이스 이미지

- from이란 시작점을 의미하는데, Dockerfile에서 FROM은 이걸 바탕으로 시작한다는 의미임

- nginx는 이건 이미지의 이름임. 이미지는 운영체제 + 프로그램 + 설정을 하나로 묶은 덩어리임, 웹서버를 위한 프로그램으로 인터넷에서 웹 페이지를 보여주는 일을 하는 소프트웨어임

- latest는 최신 버전의 nginx 웹 서버를 가져온다는 의미

더보기

root@host:~# mkdir /docker
root@host:~# cd /dockerroot@host:/docker# vi Dockerfile

root@host:/docker# docker build -t mynginx:1 .

 docker build: 이미지를 만들겠다는 의미임.

 -t mynginx:1: 이미지 이름과 버전을 설정하는 옵션임

뒤에 붙은 :1은 내가 만든 파일 버전 번호임, 앞으로 추가로 더 만들 때 숫자만 바꿔주면 됨

-t: tag

 . : 현재 디렉터리

- # 베이스 이미지라는 주석을 같은 줄에 남기면 안 되고, 다음 줄에 작성해야 됨.

- 안 그러면 위와 같은 error가 발생함.

root@host:/docker# docker image ls

root@host:/docker# docker rm -f $(docker ps -qa)
3f5f5d42ce3a
9f34d840b4da
84275b56ac90
2e4b8f2033da
2084946d521f
ae1a73192613

- 이미지의 이름은 다르지만 모든 레이어가 동일하기 때문에 이미지를 참조하고 있음.

 

root@host:/docker# docker run -dp 8080:80 --name myweb mynginx:1

docker run: 컨테이너를 실행하는 명령어

-> 이미지에서 실제로 실행되는 프로그램을 만들겠다는 의미

-> 아까 만들었던 mynginx:1을 실행 시키겠다는 의미임

 

-d: 백그라운드 실행

-> detached mode의 약자임

-> 백그라운드에서 실행하겠다는 뜻임 = 명령어를 실행하고 나서 터미널을 다른 작업을 할 수 있도록 그대로 두고 컨테이너를 실행시키겠다는 의미임

 

p 8080:80: 포트 매핑

- 외부에서 컨테이너에 접근할 수 있는 포트를 설정한 것

- 8080은 호스트 머신의 8080포트임. 즉, localhost:8080 하면 됨

- 80은 컨테이너 내에서 실행되는 애플리케이션 포트임. 이 부분은 mynginx:1 이미지 안의 웹 서버가 실행되는 포트임/ 그러니까 엔지넥스나 http는 80번으로 열림, 컨테이너 안에서 80번으로 열린다는 의미임

 

root@host:/docker# curl localhost:8080

- 만약에 curl이 안된다면 systemctl restart docker 실행

WORKDIR: 디렉터리 지정

-> 재지정전까지 영구적으로 유지

-> cd 대신 사용하면 됨. 되도록이면 cd를 안 쓰는 게 좋음

-> 컨테이너에 접속했을 때 존재하는 디렉터리가 마지막으로 지정한 WORKDIR이 됨. 

더보기

pwd

- Dockefile의 마지막 WORKDIR

FROM nginx:latest
# 베이스 이미지
WORKDIR /usr/share/nginx/html
#작업디렉터리 변경

 

root@host:/docker# docker build -t mynginx:2 

-> 현재 디렉터리의 Dockerfile을 토대로 mynginx:2라는 이미지를 만들어라.

root@host:/docker# docker build -t mynginx:2.

root@host:/docker# docker run -dp 8082:80 --name myweb2 mynginx:2

- 이미지를 생성하면서 a라는 디렉터리에서 a-1 작업 후에 b디렉터리에서 b-1 작업을 해야 함. cd로 이동을 하는 게 아니라 WORKDIR a 한 후 a-1 작업을 끝내고 다시 WORKDIR b 후에 b-1 작업을 하면 됨.

COPY: 호스트의 파일이나 폴더를 컨테이너 이미지에 삽입

더보기

root@host:/docker# echo copy_test > index.html

root@host:/docker# docker build -t mynginx:3 .

root@host:/docker# docker run -dp 8083:80 --name myweb3 mynginx:3

-> WORKDIR에 index.html이 잘 복사된 걸 확인 가능함.

COPY <호스트파일> <컨테이너파일>

COPY <호스트경로> <컨테이너경로>

- 파일은 파일로, 폴더는 폴더로 하면 실수할 여지가 줄어든다.

- 이번에는 경로 복사

root@host:/docker# vi Dockerfile 
root@host:/docker# docker build -t mynginx:4 .
root@host:/docker# docker run -dp 8084:80 --name myweb4 mynginx:4
root@host:/docker# docker exec myweb4 ls

50x.html
Dockerfile
index.html

 

ADD: 웹상에 존재하는 파일도 가져올 수 있고, tar로 압축된 파일은 압축이 자동해제

-> Dockerfile에서 파일을 복사하는 명령어임. 이 명령어는 호스트 시스템에서 Docker이미지로 파일을 추가할 때 사용됨.

COPY와 비슷, 되도록이면 COPY를 쓰자

 

root@host:/docker# tar -cvf test.tar index.html

-c: 압축파일 생성

v: 과정 출력

f: 파일 test.tar

 

root@host:/docker# vi Dockerfile

- ADD: 파일을 추가하는 작업을 수행함

- test.tar .: 호스트 컴퓨터에 있는 파일 또는 디렉토리임. 

-> 여기서는 test.tar라는 tar 압축 파일을 Docker이미지로 복사하고 있음. 이 파일은 현재 디렉토리에 있어야 함 

root@host:/docker# docker run -dp 8085:80 --name myweb5 mynginx:5

 

root@host:/docker# curl localhost:8085
copy_test

- 압축이 해제되어 index.html 파일이 잘 보이는 걸 확인 가능함

 

ADD이랑 COPY의 차이점

-> ADD는 자동으로 압축 해제하거나 URL을 통해 파일을 다운로드 할 수 있음

-> 하지만 COPY는 단순히 파일을 복사만 함. 압축 파일을 해제하거나 URL에서 다운로드하지 않음

RUN: 컨테이너 이미지 빌드 단계에서 수행되는 명령

더보기

- RUN명령으로 cd/ usr/share/nginx/html을 수행했지만, 결론적으로는  그다음 레이어의 COPY라는 명령을 수행할 때는 RUN 레이어의 수행결과가 반영되지 않음. 왜냐하면 레이어끼리는 서로 독립적이기 때문임.

root@host:/docker# docker run -dp 8086:80 --name myweb6 mynginx:6
root@host:/docker# docker exec -it myweb6 bash

root@36e608450499:/# cat index.html
copy_test
root@36e608450499:/# cat /usr/share/nginx/html/index.html 

어떤 명령을 여러 개 수행하고 싶다면 &&으로 묶어서 길게 써서 사용하자.

RUN <명령어 1> && <명령어 2> && <명령어 3>...

ex) RUN apt update -y && apt install -y <패키지 2> && systemctl restart <패키지>

실습)  FROM, RUN , WORKDIR 명령을 활용하여 댕댕이 템플릿을 포함하는 도커이미지를 myhttpd:1 이라는 이미지를 생성해서 테스트해 보세요. 베이스이미지는 httpd:latest로 하고, 이 이미지로 컨테이너를 띄웠을 때 211.183.3.100:9090 을 쳤을 때 웹페이지가 뜨도록 해보세요.

더보기

mkdir copy

cd /copy

 

root@host:/docker/copy # wget https://www.free-css.com/assets/files/free-css-templates/download/page296/neogym.zip

 

root@host:/docker/copy# unzip neogym.zip

root@host:/docker/copy# mv neogym yum

root@host:/docker/copy# mv neogym-html yum
root@host:/docker/copy# vi Dockerfile

root@host:/docker/copy# docker build -t myhttpd:1 .

root@host:/docker/copy# docker run -dp 9090:80 --name yum myhttpd:1

CMD: 컨테이너가 실행되는 단계에서 수행할 명령

- 컨테이너를 생성 및 실행했을 때 컨테이너 내부에서 프로세스가 포어그라운드로 잘 동작하도록 하는 명령

- 보통은 맨 마지막에 한번 적어줌

더보기

root@host:/docker/copy# docker inspect yum

vi Dockerfile

- httpd 컨테이너: httpd -D FOREGROUND

-> CMD형태로 표현하면 됨

 

CMD

-> Dockerfile에서 컨테이너가 시작될 때 실행할 명령어

-> Apache 서버의 옵션임. 이 옵션은 Apache를 특정 모드로 실행할 때 사용됨.

-> FOREGROUND: Apache 서버를 백그라운드가 아닌 포그라운드에서 실행하겠다는 의미임. 컨테이너에서는 포그라운드로 실행해야만 계속 실행 상태를 유지하면서 로그를 볼 수 있음.

 

root@host:/docker/copy# cd ..
root@host:/docker# mkdir cmd
root@host:/docker# cd cmd

root@host:/docker/cmd# vi Dockerfile

root@host:/docker/cmd# docker build -t cent:1 .

root@host:/docker/cmd# docker run -d --name sleep cent:1

- 억지로 컨테이너 내부의 포어그라운드 프로세스를 만들어줌

ENTRYPOINT ["sleep"]

-> Dokerfile에서 컨테이너가 실행될 때 실행되는 명령어

-> 컨테이너가 시작될 때 반드시 실행되어야 하는 명령어

-> CMD랑 다르게 ENTRYPOINT는 다른 명령어를 지정해도 고정된 명령어로 실행됨

 

root@host:/docker/cmd# docker rm -f $(docker ps -qa)

# 삭제

root@host:/docker/cmd# docker build -t entry:1 .

 

root@host:/docker/cmd# docker run -dp 5959:80 --name etest entry:1

# CMD와 크게 다른게 없어 보

- sleep infinity test라는 명령으로는 컨테이너가 포어그라운드가 될 수 없음

root@host:/docker/cmd# docker build -t entry:2 .

 

root@host:/docker/cmd# docker run -dp 5952:80 --name etest2 entry:2 120

- CMD는 결국 Dockerfile에서도 지정 가능하고 컨테이너를 실행할 때도 이미지 오른쪽에 넣어줄 수 있음. 결국 컨테이너를 실행하면서 CMD를 적어주면 Dockerfile에서 작성했었던 CMD는 무시됨.

실습) ubuntu:latest를 베이스이미지로 하여 컨테이너를 띄웠을 때 간단한 웹페이지가 뜨는 myubun:1 이라는 컨테이너이미지를 만들어 보세요.

더보기

root@host:/docker/myubun# docker run -it --name ubun ubuntu:latest bash

- 컨테이너는 기본적으로 root사용자가 아님

root@c8220f389059:/# apt update -y      

- 컨테이너가 구닥다리니까 먼저 update를 해야 됨

root@c8220f389059:/# apt install -y nginx

root@7a6c9030ddd2:/# nginx -g 'daemon off;'

# 업데이트, 설치, nginx동작 => 우리가 도커파일로 작성해야 하는 내용.

 

vi Dockerfile

FROM ubuntu:latest

RUN apt update -y && apt install -y nginx 

CMD ["nginx","-g","daemon off;"]

 

root@host:/docker/cmd# docker build -t myubun:1 .

root@host:/docker/cmd# docker run -dp 5656:80 --name web myubun:1

 

 

root@host:/docker/cmd# docker image prune -fa

# 이미지 전체 삭제

EXPOSE : 포트를 노출. 사실상 의미 없음.

- docker run을 통해 컨테이너 생성할 때 -P(대문자 P)의 경우엔 호스트의 포트를 랜덤 하게 부여할 수 있음

- 이때 컨테이너의 포트는 EXPOSE 된 포트가 명시됨

- -p 옵션을 사용할 때만 유용한 명령어다. -p(publish) 할 때는 의미 없음.

더보기

 root@host:/docker/cmd# cd ..

root@host:/docker# mkdir expose

root@host:/docker# cd expose/

root@host:/docker/expose# vi Dockerfile

FROM nginx:latest

EXPOSE 80

root@host:/docker/expose# docker build -t expose:1 .

root@host:/docker/expose# docker run -dP --name exptest expose:1

- 대문자 dP

ENV : 환경변수 선언

더보기

vi Dockerfile

 

root@host:/docker/expose# docker run -it --name env envtest:1 bash
root@9d969dcc6290:/# echo $ENVTEST

Dockerfile 작성법

- 컨테이너 레지스트리(Registry, 저장소)

- 레지스트리 = 도서관. 레포지스토리 = 책장, 태그 = 책(버전별로)

- 다양한 레지스트리가 존재함

도커 허브 = 퍼블릭한 레지스트리

- 클라우드는 기본적으로 AWS ECR, GCP GCR, Azure ACR 같은 프라이빗 및 퍼블릭 레지스트리 서비스를 제공함, 내가 Harbor나 Nexus 같은 사설 레지스트리를 직접 구축할 수도 있음.

더보기

도커이미지를 레지스트리에 올리려면

1. 애초에 docker build를 레지스트리 주소로 만들면 됨

2. 기존의 이미지를 올리고 싶으면, 기존 이미지를  docker tag라는 명령으로 새로 만들어 주면 됨

 

root@host:/docker# vi Dockerfile

FROM nginx:latest

root@host:/docker# docker build -t oolralra/myweb:1.

 root@host:/docker# docker tag myweb:1 choyunji/myweb:2

- 만약, 기존 이미지를 레지스트리에 올리고 싶다면 tag명령으로 새로운 태그를 만들면 됨

- image가 잘 생성된 걸 볼 수 있음

이제 도커에 로그인해 보자

 

root@host:/docker# docker login -u choyunji

실습) ubuntu:latest를 베이스이미지로 하여 tomcat을 설치하고 index.jsp를 통해 컨테이너의 아이피를 보여주는 간단한 파일을 배포하는 이미지를 만든 후 도커 허브에 push 해서 테스트해보세요. 레포이름은 tom, 태그는 81

 

curl localhost:8989 를 쳤을 때 index.jsp 파일이 보이면 됩니다.

더보기

root@host:/docker# mkdir tomcat_docker
root@host:/docker# cd tomcat_docker/
root@host:/docker/tomcat_docker# vi Dockerfile

root@host:/docker/tomcat_docker# docker build -t tom:81 .

root@host:/docker/tomcat_docker# docker run -d -p 8989:8080 --name tomcat81 tom:81 

FROM ubuntu:latest
RUN apt-get update && apt-get install -y openjdk-11-jdk wget && wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.100/bin/apache-tomcat-9.0.100.tar.gz && tar -xvzf apache-tomcat-9.0.100.tar.gz && mv apache-tomcat-9.0.100 /opt/tomcat
EXPOSE 8989
RUN echo '<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>' > /opt/tomcat/webapps/ROOT/index.jsp && \
    echo 'hello world' >> /opt/tomcat/webapps/ROOT/index.jsp
CMD ["/opt/tomcat/bin/catalina.sh", "run"]

root@host:/docker/tomcat_docker# curl http://localhost:8989

root@host:/docker/tomcat_docker# docker build -t choyunji/tomcat81:1 .

root@host:/docker/tomcat_docker# docker push choyunji/tomcat81:1

-> 먼저 이미지가 잘 동작하는지 docker run을 통해 테스트 후에 push를 하는게 좋

-

강사님 풀이

1. 필요한 패키지 설치 -ubuntu에서는 update 후에 openjdk-11-jdk unzip wget

2. 압축해제 후 , tomcat 디렉터리 이름 변경 후 권한 부여

3. 호스트에 미리 만들어 놓은 index.jsp파일도 넣어주고

4. tomcat을 foreground로 동작시키기 위한 CMD 구성

 

root@host:/docker/tom# docker run -it --name tomcat ubuntu:latest bash

- 들어가서 각 명령이 잘 먹히는지 확인

 

root@379a9ca335a3:/# apt update -y

root@379a9ca335a3:/# apt install -y openjdk-11-jdk unzip wget

wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.39/bin/apache-tomcat-10.1.39.zip

root@379a9ca335a3:/# unzip apache-tomcat-10.1.39.zip

root@379a9ca335a3:/# mv apache-tomcat-10.1.39 tomcat

root@379a9ca335a3:/# rm -rf apache-tomcat-10.1.39.zip

root@379a9ca335a3:/# chmod 777 -R tomcat

root@379a9ca335a3:/# ./tomcat/bin/catalina.sh run

 

- 창을 하나 더 열어서

- 컨테이너 IP조회후 접속 => tomcat 이 잘 동작하는걸 확인.

도커 이미지 지울 때

docker rmi choyunji/tom:1

728x90