이 포스팅은 위키북스의 시작하세요! 도커/쿠버네티스 를 보고 공부한 내용을 바탕으로 하고 있습니다. (문제가 된다면 비공개 처리하겠습니다😂😂)
이미지 출처 : https://data-newbie.tistory.com/516
지금까지는 단순히 공식 허브에 이미지를 다운받아서 컨테이너를 생성하고 그 안에서 각종 도구를 사용하고나 파일을 생성하는 과정을 진행했었습니다.
하지만, 이렇게 되면 매번 애플리케이션을 동작하는 환경을 구성하기 위해 패키지를 설치하고 환경설정하는 과정을 반복해야 합니다.
이런 문제를 간소화하기 위해서 Dockerfile
이란게 존재합니다. Dockerfile은 컨테이너에 설치해야하는 패키지, 소스코드, 명령어, 환경변수설정 등을 기록한 하나의 파일입니다. 그리고 이를 빌드하면 자동으로 이미지가 생성됩니다. 이렇게 되면 앞으로는 애플리케이션 빌드 및 배포를 자동화
할 수 있게됩니다.
근데 생각해보면 컨테이너에서 작업을 한다음에 이미지로 커밋하면 되는거 아닌가? 뭐.. 그럴수도 있겠습니다만 권장하는 방법은 Dockerfile을 이용해서 빌드하고 배포하는게 더 좋다고 합니다. (애플리케이션 패키지 설치를 명확히 함. 이미지 생성을 자동으로 함. 쉽게 배포 가능 등등)
VS Code에서 확장도구를 설치하면 쉽게 작성할 수 있을겁니다.
# 1. 우분투 설치
FROM ubuntu:18.04
# 2. 메타데이터 표시
LABEL "purpose"="practice"
# 3. 업데이트 및 아파치 설치
RUN apt-get update
RUN apt-get install apache2 -y
# 4. 호스트에 있는 파일을 추가
ADD test.html /var/www/html
# 5. 작업공간 이동(=cd)
WORKDIR /var/www/html
# 6. 거기서 test2.html 파일생성
RUN ["/bin/bash", "-c", "echo hello > test2.html"]
# 7. 포트 80번 노출 지정
EXPOSE 80
# 8. 컨테이너 생성시 시작명령어
CMD apachectl -DFOREGROUND
- FROM : 생성할 이미지의
베이스가 될 이미지
를 뜻합니다. 반드시 한번 이상 입력해야 합니다.- LABEL : 이미지에
메타데이터
를 추가합니다. (나중에 원하는 조건의 컨테이너, 이미지 등을 쉽게 찾을 수 있도록 도와주기 때문에 기억해두는게 좋습니다)- RUN : 이미지를 만들기 위해 컨테이너
내부에서 명령어
를 실행합니다. (여기서 주의할 점은 설치과정에서 별도의 입력이 불가능하기 때문에 apache2를 설치할 때 뒤에-y
를 붙여줘야 합니다.- ADD :
파일을 이미지에 추가
합니다. 여기서는 Dockerfile이 위치한 폴더에 test.html 파일을 가져와서 이미지의 /var/www/html 디렉터리에 추가합니다.- WORKDIR : 명령어를 실행할 디렉토리. 배시 셸에서의
cd 명령어와 동일한 기능
을 합니다.- EXPOSE: 이미지에서
노출할 포트
를 설정합니다.- CMD :
컨테이너가 시작될 때마다 실행할 명령어
. Dockerfile에서 한번만 사용할 수 있습니다.
부가적으로 RUN ["/bin/bash", "-c", "echo hello > test2.html"] => /bin/bash 셸을 이용해 echo hello > test2.html를 실행하라는 뜻입니다.
이를 종합해봤을때 ubuntu18:04를 이용해 컨테이너를 생성합니다. 그리고 그 안에서 apt-get update를 하고 아파치를 설치합니다. 호스트에 있는 test.html을 /var/www/html에 추가한다음, 그 폴더로 이동한 후에 test2.html을 생성합니다. 마지막으로 80번 포트를 노출시킬 포트로 설정한 다음 CMD 명령으로 이미지 빌드를 마칩니다.
이제 서버에다가 아래와 같이 해준다음에, 위에서 작성한 도커파일을 추가해줍니다.
$ mkdir dockerfile
$ cd dockerfile
$ echo test >> test.html
앞서 만든 도커파일을 빌드해봅니다.
$ docker build -t mybuild:0.0 ./
-t 옵션
은 생성될 이미지 이름을 설정합니다. build 명령 끝에는 Dockerfile이 저장된 경로를 입력합니다. 여기서는 현재 디렉토리라고 입력했습니다.
빌드를 시작하면 step 1부터 9단계까지 자기가 알아서 실행하고 있는 것을 볼 수 있습니다.
이미지도 잘 생성되었으니 컨테이너를 생성하고 실행시켜보겠습니다. 잘 나오는 것을 확인할 수 있습니다.
$ docker run -d -p 80:80 --name myserver mybuild:0.0
빌드를 시작하면 가장 먼저 시작하는 게 뭔지 나와있습니다. 도커파일이 위치한 디렉터리를 빌드 컨텍스트라고 부르고 도커는 가장먼저 빌드 컨텍스트를 읽어들입니다. (따라서 루트 디렉터리 같은 곳에서 빌드하지 않도록 주의해야합니다)
아니면, gitignore 파일처럼 빌드 컨텍스트 읽을때 제외할 폴더 및 파일을 명시할 수 있습니다
빌드과정을 유심히 살펴보면 눈에 띄는게 바로 Removing~container입니다. 이 이유는 ADD, RUN등의 명령이 실행될때마다 새로운 컨테이너가 하나씩 생성되며 이를 이미지로 커밋하는 것이기 때문입니다. (오... [컨테이너 생성 -> 명령어 실행 -> 레이어 생성 -> 이미지로 커밋] * 반복
이라는 소리가 되네요)
한번 이미지 빌드를 마치고 난뒤 다시 같은 빌드를 진행하면 이전의 이미지빌드에서 사용했던 캐시를 사용합니다.
# Dockerfile2 작성
FROM ubuntu:18.04
LABEL "purpose"="practice"
RUN apt-get update
$ docker build -f Dockerfile2 -t mycahe:0.0 ./
Using cache
라는 출력내용과 함께 빌드과정이 진행되지 않고 바로 이미지가 생성되었습니다. 즉, 이전에 빌드했던 Dockerfile에 같은내용이 있다면 build명령어는 이를 새로 빌드하지 않고 같은 명령어 줄까지 이전에 사용한 이미지 레이어를 활용해 이미지를 생성하는 것입니다.
단, 캐시기능이 문제가 되는 경우도 있습니다. git clone
을 통한 명령어를 사용한 빌드가 일어난다고 가정했을때 실제 git저장소에 소스코드 변경이 생겨도 매번 빌드할때마다 캐시기능 때문에 고정된 소스코드를 사용하게 될 겁니다.
이럴때는 --no-cache
옵션을 추가해주면 캐시기능을 끄고 빌드할 수 있습니다.
$ docker build --no-cache -f Dockerfile2 -t mycahe:0.0 ./
일반적으로 애플리케이션을 빌드하려면 많은 의존성 패키지 및 라이브러리를 필요로합니다. 그래서 이미지자체의 용량이 커지거나 최종적으로 실행할 때 불필요한 라이브러리들이 있을 수 있습니다.
이럴 때는멀티 스테이지
를 활용하여 여러개의 FROM 명령어를 사용하여 최종적으로는 반드시 필요한 실행 파일만 최종 이미지 결과물에 포함시켜 이미지의 용량을 줄일 때 유용합니다.
예를 들어, 여기서는 Hello World를 출력하는 Go 소스코드를 작성한 뒤, golang 이미지를 기반으로 Go소스코드를 컴파일하고 출력하는 Dockerfile을 작성해 빌드해보도록 하겠습니다.
// main.go
package main
import "fmt"
func main(){
fmt.Println("hello world")
}
# Dockerfile3
FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
CMD ["./mainApp"]
$ docker build -f Dockerfile3 -t go_helloworld ./
넵... 이미지 크기가 엄청나네요. 이번에는 이미지 크기를 줄이기 위해 멀티 스테이지 빌드 방법을 사용해보겠습니다.
# Dockerfile3 수정
FROM golang
ADD main.go /root
WORKDIR /root
RUN go build -o /root/mainApp /root/main.go
FROM alpine:latest
WORKDIR /root
COPY --from=0 /root/mainApp .
CMD ["./mainApp"]
2개의 FROM을 통해 2개의 이미지를 적어주었습니다. 여기서 주의해서 볼 곳은 두번째 FROM에서 /root/mainApp에 존재하는 파일을 .로 이동합니다. 이 때 --from=0은 첫 번째 FROM에서 빌드된 이미지의 최종 상태를 의미합니다. (= 즉, 첫번째 FROM 이미지에서 빌드한 /root/mainApp파일을 두번째 FROM에 명시된 이미지 alpine:latest 이미지에 복사하는것 )
참고로 alpine은 알파인 리눅스를 의미합니다. 용량이 80M인 초경량화된 배포판이므로 Embbeded 나 네트웍 서버등 특정 용도에 적합하며 특히 도커(docker)에 채택되어 5M 크기의 리눅스 이미지로 유명합니다. (도커에서 꽤나 유명한듯...)
출처 : https://www.lesstif.com/docker/alpine-linux-35356819.html
환경변수를 설정할 수 있습니다. 개인적으로 저는 많이 썼었습니다.
ENV test /home
export test=/home
이랑 같은 의미...
호스트와 공유할 컨테이너 내부의 디렉터리 설정
VOLUME /home/volumn
build 명령어를 실행할때 추가로 입력받아 도커파일 내에서 사용될 변수의 값을 설정
USER로 컨테이너 내에서 사용될 사용자 계정의 이름이나 UID를 설정하면 그 아래 명령어는 해당 사용자 권한으로 실행되도록 설정(권장)
ADD와 COPY는 기능적으로 같은역할로써 이미지에 파일을 복사해줍니다. 다만 차이점은 COPY은 로컬의 파일만 이미지에 추가할 수 있지만, ADD는 URL 및 tar 파일에서도 파일을 추가할 수 있습니다. (권장되는 방법은 COPY라고 하는군요)
생략...
안녕하세요 운영자님
인카토스입니다.
먼저, 댓글로 인사를 드리게 된 점 양해 부탁 드립니다.
이렇게 연락 드린 이유는 이번에 저희가 제작한 도커 각티슈케이스 제품 협찬을 제안드리고 싶어서 연락 드렸습니다.
개발자들에게 많은 사랑은 받은 각티슈케이스입니다.
저희 상품 블로그 포스팅이 가능하실지 여쭙고자 연락드렸습니다.
포스팅이 어려우시다면 도커 글 하단에 이미지와 링크만 좀 달아주셔도 좋을거같습니다.
연락드릴수 있는방법이 댓글밖에 보이지 않아 이렇게 먼저 연락드립니다.
협찬제안에 긍정적인 검토 부탁드리고 제안이 마음에 드신다면 하기 메일로 메일주시면 제품 보내드리도록 하겠습니다.
sungjh0726@naver.com
협찬제품 링크 : https://incatos.shop/surl/P/11
감사합니다.
인카토스 드림.
감사합니다!