Image 생성을 위한 Dockerfile 명령어
Dockerfile
- Dockerfile은 Docker에서 동작하는 컨테이너의 구성 정보를 프로비저닝(Provisioning)한 텍스트 template 파일이다.
- Docker 이미지는 컨테이너가 런타임 환경으로 동작하기 위해 필요한 특정 기술 또는 서비스를 사전에 구축한 환경이다.
- Dockerfile은 애플리케이션 배포에 필요한 컨테이너 인프라를 코드 형태로 정의한 파일이다.(IaC-Infrastructure as Code)
Dockerfile 명령어
- FROM(layer)
- (필수) 생성하려는 이미지의 베이스 이미지 지정으로 hub.docker.com에서 제공하는 공식(오피셜, official) 이미지 권장하며 이미지 태그는 도커 허브에서 여러 태그가 버전 정보처럼 제공된다.
- 이미지를 선택할 때 작은 크기의 이미지(slim)와 리눅스 배포판인 알파인(alpine) 이미지를 권장한다. 하지만, 모든 애플리케이션이 동일하지는 않다.
- 태그를 넣지 않으면 latest로 지정된다
- 사용방법
FROM ubuntu:20.04
FROM pythonL3.9-slim-buste
FROM monog:4.4.4-bionic
- MAINTAINER
- 일반적으로 이미지를 빌드한 작성자 이름과 이메일을 작성한다.
- 사용방법
MAINTAINER junseong.kim<junseongday@gmail.com>
- LABEL(layer)
- 사용방법
LABEL purpose=’Nginx for webserver’
LABEL version=’1.0′
LABEL description=’web service application using Nginx’ - 권장사항
LABEL purpose=’Nginx for webserver’\
version=’1.0’\
description=’web service application using Nginx’
- 사용방법
- RUN(layer)
- 설정된 기본 이미지에 패키지 업데이트, 각종 패키지 설치, 명령 실행 등을 작성한다. 하나 이상 작성 가능하다.
- 사용방법
RUN aptupdate
RUN apt -y install nginx
RUN apt -y install git - 권장사항
RUN apt update && apt install -y nginx \ git \ vim \ curl && \
apt clean -y && \
apt autoremove -y && \
rm -rfv /tmp/* /var/lib/apt/lists/* /var/tmp/*
- CMD
- 생성된 이미지를 컨테이너로 실행할 때 실행되는 명령이고, ENTRYPOINT 명령문으로 지정된 커맨드에 디폴트로 넘길 파라미터를 지정할 때 사용된다. 여러 개의 CMD를 작성해도 마지막 하나만 처리된다. 일반적으로 이미지가 컨테이너 실행 시 애플리케이션 데몬이 실행되도록 하는 경우 유용하다.
- 사용방법
[Shell 방식]
CMD apachectl -D FOREGROUND[Exec 방식]
CMD [“/usr/sbin/apachectl”, “-D”, “FOREGROUND”]
CMD [“nginx”, “-g”, “daemon off;”]
CMD [“python”, “app.py”]
- ENTRYPOINT
- CMD와 마찬가지로 생성된 이미지가 컨테이너로 실행될 때 사용되지만, 다른 점은 컨테이너가 실행될 때 명령어 및 인자 값을 전달하여 실행한다.
- 사용방법
ENTRYPOINT [“npm”, “start”]
ENTRYPOINT [“python”, “runapp.py”]ADD ./entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT [“/bin/bash”, “/entrypoint.sh”]
- COPY(layer)
- 호스트 환경의 파일, 디렉터리를 이미지 안에 복사하는 경우 작성한다. 단순한 복사 작업만 지원한다. 빌드 작업 디렉터리 외부의 파일은 COPY 할 수 없다. 복사가 필요한 명시적인 작업인 경우는 ADD 보다는 COPY 권장한다.
- 사용방법
COPY index.html /usr/share/nginx/html
COPY ./runapp.py /
- ADD(layer)
- 호스트 환경의 파일, 디렉터리를 이미지 안에 복사하는 경우 뿐만 아니라, URL 주소에서 직접 다운로드하여 이미지에 넣을 수도 있고, 압축 파일(tar, tar.gz)인 경우에는 지정한 경로에 압축을 풀어서 추가한다. 단, 빌드 작업 디렉터리 외부의 파일은 ADD 할 수 없고, 디렉터리 추가시 에는 /로 끝나야 한다.
- 사용방법
ADD index.html /usr/share/nginx/html
ADD http://example.com/view/customer.tar.gz /workspace/data/
ADD website.tar.gz /var/www/html
- ENV(layer)
- 이미지 안에 각종 환경 변수를 지정하는 경우 작성한다. 애플리케이션 사용을 쉽게 하려면 사전에 구성되야 하는 환경변수들이 있다. 또한, 반복된 표현이 사용되는 경우에도 환경 변수 설정을 권장한다.
- 사용방법
ENV JAVA_HOME /usr/lib/jvm/iava-8-oracle
ENV PATH /usr/local/nginx/bin:$PATH
ENV Python 3.9ENV NODE_VERSION v15.1.0
RUN curl -SLO “http://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-linux-x64.tar.gz” \
&& tar -xzf “node-$NODE_VERSION-linux-x64.tar.gz” -C /usr/local –strip-components=1 \
&& rm “node-$NODE_ VERSION-linux-x64.tar.gz”
- EXPOSE
- 컨테이너가 호스트 네트워크를 통해 들어오는 트래픽을 리스팅하는 포트와 프로토콜을 지정하기 위해 작성한다.
- 사용방법
EXPOSE 80, EXPOSE 80/tcp
EXPOSE 443
EXPOSE 8080/udp
- VOLUME
- 봄륨을 이미지 빌드에 미리 설정하는 경우 작성한다. 도커 컨테이너에서 사용된 파일과 디렉터리는 컨테이너 삭제와 함께 사라지낟. 따라서, 사용자 데이터의 보존과 지속성을 위해 볼륨 사용을 권장한다. VOLUME으로 지정된 컨테이너의 경로는 불륨의 기본경로 /var/lib/docker와 자동으로 연결된다.
- 사용방법
VOLUME /var/log
VOLUME /var/www/html
VOLUME /etc/nginx
VOLUME [“/project”]
- USER
- 컨테이너의 기본 사용자는 root다. 애플리케이션이 권한없이 서비스를 실행할 수 있다면 USER를 통해 다른 사용자로 변경하여 사용한다.
- 사용방법
RUN [“useradd”, “kevinlee”]
USER kevinlee
RUN [“/bin/bash”, “-C”, “date”]
또는,
RUN groupadd -r mongodb && \ useradd –no-log -r -g monodb mongodb
- WORKDIR
- 컨테이너 상에서 작업할 경로(디렉터리) 전환을 위해 작성한다. WORKDIR을 설정하면 RUN, CMD, ENTRYPOINT, COPY, ADD 명령문은 해당 디렉터리를 기준으로 실행한다. 지정한 경로가 없으면 자동 생성되고, 컨테이너 실행 이후 컨테이너에 접속(docker exec -it my_container bash)하면 지정한 경로로 연결된다.
- 사용방법
WORKDIR /workspace
WORKDIR /usr/share/nginx/html
WORKDIR /go/src/app
- ARG
- docker build 시점에서 변수 값을 전달하기 위해 “–build-arg=인자”를 정의하여 사용한다. 비밀 키, 계정 비밀번호 같은 민감한 정보 사용시 이미지에 그대로 존재하여 노출될 위험이 있으므로 이러한 정보는 주의해야 한다.
- 사용방법
# Dockerfile에 ARG 변수를 정의하고
ARG db_name
# docker build 시 변수 값을 저장하면 이미지 내부로 인자가 전달된다.
dockerbuild –build-arg db_name=fastdb
# 입력 받은 변수 값을 다음과 같이 명령에 사용한다.
CMD db_start.sh -h 127.0.0.1 -d ${db_name}
[실습]다양한 Dockerfile build
Dockerfile build 방법
docker build -t IMAGE_NAME:TAG [-f DOCKERFILE_NAME] DOCKERFILE_LOCATION
Dockerfile build 과정 예
cd ~/fastcampus/ch09/sample vi index.html docker guild -it fc-webserver:1.0 . docker images | grep fc docker run -d --name=fc-webserver -p 8001:80 fcwebserver:1.0 curl localhost:8001
이 도커 파일을 살펴봅시다. ubuntu이미지를 기본이미지로 사용하네요. 그리고 apt-get을 업데이트하고 nginx를 설치하고 있습니다.
호스트 파일의 index.html을 /var/www/html/ 위치로 이동하며 80 포트를 노출합니다. 그리고 백그라운도로 실행합니다.
위의 사용법이 기본적인 도커 파일의 사용법입니다.
[실습1]불필요한 파일 제거를 통한 “이미지 경량화”
cd ~/fastcampus/ch09/lightweight1 vi dockerfile-myweb1 docker build -t myweb:1.0 -f dockerfile-myweb1 --no-cache .
FROM ubuntu:14.04
MAINTAINER “kevin-lee <hylee@dshub.cloud>” LABEL “purpose”=”webserver practice”
RUN apt update && apt install apache2 -y
WORKDIR /var/www/html
COPY index.html . EXPOSE 80 CMD apachectl -D FOREGROUND
dockerfile-myweb1을 보면 ubuntu를 기본 이미지로사용하고 있고 apache2를 설치하고 작업폴더를 /var/www/html폴더로 설정했습니다. 아파치가 설치된 우분투를 만드는 이미지입니다.
패키지 설치를 위해 다운로드한 패키지 잔여물을 autoremove, autoclean, rm 등으로 제거하여 경량화 하자.
vi dockerfile-myweb2 docker build -t myweb:2.0 -f dockerfile-myweb2 --no-cache .
FROM ubuntu:14.04
MAINTAINER "kevin-lee <hylee@dshub.cloud>" LABEL "purpose"="webserver practice" RUN apt update && apt install apache2 -y && \
apt clean autoclean && \
apt autoremove -y && \
rm -rfv /tmp/* /var/lib/apt/lists/* /var/tmp/*
WORKDIR /var/www/html COPY index.html . EXPOSE 80 CMD apachectl -D FOREGROUND 경량화를 위해서 설치후 불필요한 파일들을 삭제합니다.
이미지를 alpine linux로 변경하여 크기를 줄이자
vi dockerfile-myweb3 docker build -t myweb:3.0 -f dockerfile-myweb3 --no-cache .
2번째 방법으로 불필요한 잔여물을 제거하면 13MB줄어든걸 알수있습니다. 하지만 그리 큰 변화는 아닌거 같습니다. alpine을 기본 이미지로 사용한 것이 가장 극적인 변화가 보이네요. alpine을 사용하고 불필요한 파일을 제거하는게 가장 베스트인거 같습니다.
[실습2] scratch를 활용한 “이미지 경량화”
sudo apt -y install gcc vi go-to-lightweight-image.c #include <stdio.h> int main() { printf("Go to lightweight image!\n"); return 0; } gcc --static -o go-to-lightweight-image go-to-lightweight-image.c ./go-to-lightweight-image vi dockerfile-ubuntu FROM ubnuntu:20.04 COPY go-to0lightweight-image / CMD["/go-to-lightweight-image"] vi dockerfile-scratch FROM scratch COPY go-to0lightweight-image / CMD["/go-to-lightweight-image"] docker build -t lightweight:1.0 -f dockerfile-ubuntu --no-cache . docker build -t lightweight:2.0 -f dockerfile-scratch --no-cache . docker images lightweight docker run -it lightweight:!.0 docker run -it lightweight:2.0
이미지를 하나 만들어서 하나는 우분투 위에서 구동하는 이미지를 만들고 다른 하나는 scratch에서 구동하도록 만들었습니다. scratch는 아무것도 없는 거를 말합니다. 용량차이가 651kb vs 66.3mb 이네요.
[실습3]multi-stage build를 통한 “이미지 경량화”
cd ~/fastcampus/ch09/multi-stage vi gostarg.go
고랭 파일을 이용해서 이미지를 만드는데 두번째 방법에서 multi-stage방법을 사용하고 있네요. 먼저 이미지를 설정하고 그걸 scratch를 기반으로 아래에서 사용합니다.
vi dockerfile-go1 FROM golang:1.15-alpine3.12 WORKDIR /app/ COPY gostart.go /app/ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /app/gostart ENTRYPOINT [ "/app/gostart" ]
vi dockerfile-go2 FROM golang:1.15-alpine3.12 AS gobuilder-stage MAINTAINER kevin,lee <hylee@dshub.cloud> LABEL "purpose"="Application Deployment using Multi-stage builds." WORKDIR /app/ COPY gostart.go /app/ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /app/gostart FROM scratch COPY --from=gobuilder-stage /app/gostart /app/gostart CMD ["/app/gostart"]
gostart.go
docker build -t goapp:1.0 -f dockerfile-go1 --no-cache . docker build -t goapp:2.0 -f dockerfile-go2 --no-cache . docker images | grep goapp docker run --name goapp1 -p 9091:9090 -d -h goapp1 goapp:1.0 docker run --name goapp2 -p 9092:9090 -d -h goapp2 goapp:2.0 curl localhost:9091 curl localhost:9092
6MB vs 300MB 차이가 나네요. 이런식으로
[실습4] multi-stage build를 통한 “이미지 경량화”
vi appstart.sh #!/bin/bash echo "Best image build, multi stage build!" chmode +x appstart.sh vi dockerfile-app1 FROM ubuntu:14.04 RUN apt-get update -y && apt-get install nginx -y COPY appstart.sh / RUN useradd kevin USER kevin ENTRYPOINT ["/appstart.sh"] vi dockerfile-app2 FROM ubuntu:20.04 as v1-stage RUN apt-get update && apt-get install nginx -y WORKDIR /app COPY appstart.sh /app stage2 FROM alpine:3.12.1 RUN addgroup -S appgroup && adduser -S kevin -G appgroup -h /home/kevin COPY --from=v1-stage /app /home/kevin USER kevin ENTRYPOINT ["sh","/home/kevin/appstart.sh"]머
멀티스테이지를 사용해서 alpine리눅스에 설치하는 실습니다.
dockerfile-app1
dockerfile-app2
docker build -t webapp:1.0 -f dockerfile-app1 --no-cache . docker build -t webapp:2.0 -f dockerfile-app2 --no-cache . docker images | grep webapp docker run webapp:1.0 docker run webapp:2.0
5MB vs 220MB이네요. 스크래치보다는 알파인으로 하는게 저는 더 좋아보이네요.
[실습5]ADD기능, *.tar.gz으로 공유 받은 압축파일 이미지에 바로 적용하기
cd ~/fastcampus/ch09/add-gz vi dockerfile-add docker build -t myweb:2.0 -f dockerfile-add . docker run -d -p 8001:80 --name=webapp3 myweb:2.0 curl lopcalhost:8001 docker exec -it webapp -it webapp3 ls -l /var/www/html
FROM ubuntu:14.04
MAINTAINER “kevin-lee <hylee@dshub.cloud>”
LABEL “purpose”=”webserver practice”
RUN apt-get update && apt-get -y install apache2 \
vim \ curl \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /etc/apt/sources.list.d/*
ADD webapp.tar.gz /var/www/html
WORKDIR /var/www/html EXPOSE 80 CMD /usr/sbin/apache2ctl -D FOREGROUND ADD로 tar.gz을 추가하면 압축해제가 되어서 풀립니다.
[실습6]간단한 python&flask 웹 서비스 배포
[실습] Nexus, Private registry 구축
sonatype Nexus private registry 구축
sudo mkdir /nexus-data sudo chown -R kevin /nexus-data docker run --name nexus -d -p 5000:5000 -p 8081:8081 -v /nexus-data:/nexus-data -u root --restart=always sonatype/nexus3 docker ps | grep nexus curl localhost:8081 // 비밀번호 확인 sudo cat /nexus-data/admin.password docker exec -it nexus cat /nexus-data/admin.password // private repository 주소 설정 sudo cat /etc/docker/daemon.json docker info docker image tag goapp:1.0 192.168.68.101:5000/goapp:1.0 docker login http://192.168.68.101:5000 docker push 192.168.68.101:5000/goapp:1.0 // hostos2 docker pull 192.168.68.101:5000/goapp:1.0 docker images | grep goapp docker run -d -p 9090:9090 --name=goapp 192.168.68.101:5000/goapp:1.0 curl localhost:9090
이미지를 관리하는 저장소로 널리 사용되는 툴입니다. 처음 로그인 할때 username을 admin 비밀번호는 서버에서 /nexus-data/admin.password에서 확인후에 로그인이 가능합니다.
/etc/docker/daemon.json
daemon.json 파일에 호스트 주소와 nexus포트를 연결해줍니다.
[실습]Python 환경 Image build
vi Dockerfile # slime 버전의 가벼운 python base image를 선택한다. FROM python:3.9-slim # /app 디렉터리를 생성하고 이동한다. WORKDIR /app # 동일 경로에 있는 파일들을 이미지 내부 경로(/app)로 복사한다. COPY requirement.txt . COPY app/static static COPY app/template template COPY app.py . # Python에 필요한 모듈을 설치한다. (선택) RUN pip install --no-cache-dir -r requirement.txt # 컨테이너로 동작 시 해당 소스를 실행한다. CMD ["python", "app.py"] docker build -t lab1-flask-app:1.0 . docker images lab1-flask-app docker run -d -p 8000:8000 --name=flask-app lab1-flask-app:1.0 docker image tag lab1-flask-app:1.0 192.168.68.101:5000/lab1-flask-app:1.0 docker push 192.168.68.101:5000/lab1-flask-app:1.0 # hostos2 docker pull 192.168.56.101:5000/lab1-flask-app:1.0
[실습] Nodejs 환경 Image build
vi Dockerfile # 공식 Node.js runtime을 base image로 사용 FROM node:20-alpine # 컨테이너 내부에 작업 경로 설정 WORKDIR /usr/src/app # 작업 경로에 package.json과 package-lock.json 파일 복사 COPY package*.json ./ # project 종속성 설치 RUN npm install # 나머지 application code를 docker image 내부에 복사 COPY . . # application port 노출하여 docker daemon과 연결 EXPOSE 3000 # application 실행 CMD ["node", "server.js"] docker build -t lab2-nodejs-app:1.0 --no-cache . docker run -d -p 3001:3000 lab2-nodejs-app:1.0
[실습] Java 환경Image build
vi Dockerfile FROM adoptopenjdk:11-jre-hotspot WORKDIR /usr/src/app COPY ./target/lab3-java-app-1.0-SNAPSHOT.jar app.jar # Include all dependencies in a lib directory COPY ./target/dependency/*.jar ./lib/ COPY ./src/main/resources/static ./static CMD ["java", "-cp", "app.jar:lib/*", "com.example.mywebapp.MainApplication"] docker build -t lab3-java-app:1.0 --no-cache . docker run -itd -p 8080:8080 --name=java-app lab3-java- app:1.0
[실습] Django 환경 Image build
vi Dockerfile FROM python:3.9-slim ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 WORKDIR /app COPY requirements.txt . # 해당 환경 변수는 python 에서 .pyc 파일을 생성하지 않게 설정 # 주로 python application의 종속성을 정의 하는 파일 경로 RUN pip install -r requirements.txt COPY . . CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] docker build -t lab4-django-app:1.0 . docker run -itd -p 8004:8000 lab4-django-app:1.0