Dokcer image를 제작하려면 먼저 image를 어떻게 만들지 명령어가 적혀있는 Dockerfile을 만들어야한다. 확장자가 없는 파일이고 원하는 경로에다가 저장하면 된다. 나는 프로젝트 루트에 저장했다.
touch Dockerfile
이후 Dockerfile이 생성되면, 몇 가지 명령어를 Dockerfile에 적어야한다. 텍스트 편집기나 IDE를 이용한다.
먼저, base가 될 image를 선택해야한다. docker hub에 가보면 사람들이 올려놓은 base image가 있다. 이 중 하나를 선택하면 되는데, 내 프로젝트는 java 11을 사용하므로 openjdk의 java 11 버전의 이미지를 사용할 것이다.
나중에 docker hub에 이미지를 업로드 할 것이기 때문에 회원가입을 해두자.
여기서는 가장 기본적인 명령어들만 사용하려고 한다. 먼저 Dockerfile의 첫 줄에 다음과 같이 적는다.
FROM openjdk:11
위에서 언급한 base image를 가져온다는 뜻이다. 유저 이름:태그
라고 생각하면 된다.
이후에 다음 명령어를 작성한다.
COPY app.jar app.jar
이 명령어는 docker 컨테이너 내부에 왼쪽에 있는 파일을 오른쪽에 있는 파일 이름으로 복사해 옮긴다는 뜻이다.
즉, 왼쪽에 오는 파일은 자신이 빌드한 jar파일의 경로가 와야 한다.
예를 들어 내가 빌드한 jar파일의 위치가 Dockerfile의 위치를 기준으로 다음과 같다고 가정하자.
./build/libs/app.jar
그렇다면 다음과 같이 작성해야 한다.
COPY ./build/libs/app.jar app.jar
COPY /build/libs/app.jar app.jar
COPY build/libs/app.jar app.jar
3개 중 어느 것이라도 상관없다.
쉘 스크립트처럼 변수를 만드는 방법도 있다.
ARG JAR_FILE_PATH=build/libs/
COPY ${JAR_FILE_PATH}app.jar app.jar
JAR_FILE_PATH
변수를 생성하는 예제다. 선언하고 나서 어디서든 예제처럼 사용하면 된다.
이후에는 마지막으로 컨테이너가 실행되면 실행할 커맨드를 입력해야한다.
ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Seoul", "./app.jar"]
평소에 사용하던 app.jar을 실행시키는 커맨드다. 정리하면 다음과 같다.
FROM openjdk:11
COPY ./build/libs/app.jar app.jar
ENTRYPOINT ["java", "-jar", "-Duser.timezone=Asia/Seoul", "./app.jar"]
위 내용이 Dockerfile에 들어가 있어야 한다.
이제 Dockerfile을 바탕으로 image를 빌드한다.
Dockerfile이 있는 경로에서 다음과 같은 명령어를 실행한다.
docker build -t hihello/test:1.5.0 .
위 명령어의 뜻을 천천히 살펴보자.
-t
는 도커의 image 이름과 태그를 지정할 수 있게 한다. 해당 옵션이 없으면 image 이름과 태그를 지정할 수 없다.
hihello/test:1.5.0
는 유저 이름/이미지 이름:태그
의 구성이다. 유저 이름은 생략할 수 있지만 생략한다면 docker hub에 업로드할 때 권한 에러가 난다. docker hub에서 가입한 닉네임으로 설정해줘야 한다.
이미지 이름은 원하는 이름으로 해주면 되고, 태그는 보통 버전으로 써준다.
.
은 중요한데, 사용할 Dockerfile의 경로를 설정해주는 것이다. 현재 우린 Dockerfile의 경로에서 작업중이므로 현재 디렉터리를 뜻하는 .
을 사용한다.
근데 여기서 추가로 주의해야할 점이 있다. docker는 vm이 아니기 때문에 해당 운영체제의 환경에 맞춰서 image를 빌드해줘야 한다.
나는 m1 mac을 사용하기 때문에 자동으로 arm/v8
아키텍쳐에 맞춰 빌드된다. 이 image는 나의 amazon linux EC2 환경인 amd64
에서 사용하지 못한다. 따라서 나와 같은 사람이라면, 다음과 같이 os와 아키텍쳐를 바꿔서 build 해줘야한다.
docker build --platform linux/amd64 -t hihello/test:1.5.0 .
참고로 가능한 os와 아키텍쳐는 base image마다 다르니, docker hub에서 가능한 항목을 찾아보는 것을 추천한다.
해당 명령어를 입력하고 build가 완료되면,
docker images
명령어를 통해 image가 정상적으로 만들어졌는지 확인하자.
만약 이미지를 잘못 만들어 삭제하고 싶다면
docker rmi hihello/test:1.5.0
으로 삭제하면 된다.
이제 image를 완성했으니 우리가 원하는 목표인 EC2에서 실행하기를 달성하기 위해, 해당 image를 docker hub에 업로드해야한다. 다음 명령어를 통해 push한다.
docker push hihello/test:1.5.0
만약 access denied
오류가 난다면 아마 두 가지 상황중 하나 일 수 있는데
첫 번째는 로그인을 하지 않은 경우다. 다음 명령어를 통해 로그인한다.
docker login
만약 이미 로그인이 되어 있다면, id와 password를 입력하라고 하지 않고 다음 내용이 출력될 것이다.
Login Succeeded
Logging in with your password grants your terminal complete access to your account.
......
그렇다면 두 번째는 내가 만든 image의 유저 이름과 로그인한 계정의 닉네임이 일치하지 않은 경우다.
나는 hihello
라는 유저 이름을 사용해서 image를 만들었다. 그렇다면 로그인한 계정의 닉네임도 hihello
여야 한다.
일치하지 않는 것으로 확인됐다면, 다음 명령어를 통해 image의 이름을 바꿔주자.
docker image tag <이전 tag> <새 tag>
docker image tag hihello/test:1.5.0 something/test:1.5.0
바꿔주고 나면 이전 image가 그대로 남아있을 것이다. 삭제해주자.
docker rmi <이전 tag>
docker rmi hihello/test:1.5.0
이제 push가 정상적으로 완료됐다면, docker hub에서 확인할 수 있을 것이다.
이제 업로드한 image를 EC2에서 내려받을 차례다. 이제부터 모든 내용은 EC2에 로그인 후 쉘에서 진행한다고 가정한다. docker도 설치되어 있다고 가정한다. EC2에 Docker 설치법은 검색하면 나오니 참고 바란다.
우선 로그인을 한다.
sudo docker login
로그인을 완료했으면, 이제 image를 다운받는다.
sudo docker pull hihello/test:1.5.0
다음 명령어를 통해 image가 잘 다운됐는지 확인할 수 있다.
sudo docker images
image가 정상적으로 다운 완료됐으면 실행한다.
sudo docker run -d --name server -p 8080:8080 hihello/test:1.5.0 --option1=false
해당 명령어를 차례차례 해석해보자.
먼저 -d
옵션은 컨테이너를 백그라운드에서 실행하는 옵션이다. EC2에서 로그아웃해도 서버가 계속 돌아가게 하기 위해서는 필수다.
로그를 남기기 위해 nohup으로도 할 수 있는데 어차피 로그를 다 볼 수 있는 명령어가 있으므로 굳이 그러지 않아도 된다.
--name
옵션은 컨테이너에 이름을 붙이는 옵션이다. 나는 server라고 이름 붙였다. 이름을 붙이는게 나중에 컨테이너를 지정할 때 편하다.
-p
옵션은 아주 중요한데, 컨테이너 내부 포트와 EC2 포트를 매핑시켜준다. 이걸 안해주면 서버가 패킷을 못 받는다. host port:container port
순으로 입력해준다.
내가 만든 spring boot 서버(container port)는 8080으로 패킷을 받기로 했고, 내 서버를 사용하는 쪽도 8080으로 request를 보낸다(host port). 따라서 8080:8080
으로 설정했다.
hihello/test:1.5.0
는 우리가 다운받은 image 이름이다.
--option1=false
는 만약 spring boot 서버를 실행할 때 옵션을 받기로 했다면 해당 위치에 넣어주면 된다.
해당 명령어 이후에 컨테이너가 실행된다. 작동중인 컨테이너들의 목록은 다음 명령어를 사용해 볼수 있다.
sudo docker ps
작동중인 컨테이너 외의 컨테이너 목록도 보고 싶다면 -a
옵션을 붙이면 된다.
컨테이너의 로그를 확인하고 싶다면, 다음 명령어를 사용한다.
sudo docker logs server
server
는 아까 붙인 컨테이너의 이름이다. 이름을 만들지 않았다면 컨테이너 목록을 확인 후 server 자리에 CONTAINER ID
를 넣으면 된다.
컨테이너를 정지하고 싶다면 다음 명령어를 사용한다.
sudo docker stop <컨테이너 id 또는 이름>
컨테이너를 삭제하고 싶다면 다음 명령어를 사용한다.
sudo docker rm <컨테이너 id 또는 이름>