파일 변경시 Docker 컨테이너 다시 빌드


93

ASP.NET Core 애플리케이션을 실행하기 위해 애플리케이션을 빌드하고 Jenkins를 사용하여 Git에서 가져온 컨테이너의 소스 코드를 복사하는 dockerfile을 생성했습니다. 따라서 내 작업 공간에서 dockerfile에서 다음을 수행합니다.

WORKDIR /app
COPY src src

Jenkins는 Git을 사용하여 호스트의 파일을 올바르게 업데이트하지만 Docker는 이것을 내 이미지에 적용하지 않습니다.

빌드를위한 기본 스크립트 :

#!/bin/bash
imageName=xx:my-image
containerName=my-container

docker build -t $imageName -f Dockerfile  .

containerRunning=$(docker inspect --format="{{ .State.Running }}" $containerName 2> /dev/null)

if [ "$containerRunning" == "true" ]; then
        docker stop $containerName
        docker start $containerName
else
        docker run -d -p 5000:5000 --name $containerName $imageName
fi

새 컨테이너 가 빌드 되기 전에 컨테이너 --rm--no-cache매개 변수 와 같은 다른 작업을 시도 docker run하고 컨테이너 중지 / 제거했습니다 . 내가 여기서 뭘 잘못하고 있는지 잘 모르겠습니다. 을 호출 COPY src src하면 레이어 ID가 발생하고 캐시 호출이 없으므로도 커가 이미지를 올바르게 업데이트하는 것 같습니다 .

Step 6 : COPY src src
 ---> 382ef210d8fd

컨테이너를 업데이트하는 데 권장되는 방법은 무엇입니까?

내 일반적인 시나리오는 다음과 같습니다. 애플리케이션이 Docker 컨테이너의 서버에서 실행 중입니다. 이제 앱의 일부가 업데이트됩니다 (예 : 파일 수정). 이제 컨테이너가 새 버전을 실행해야합니다. Docker는 기존 컨테이너를 수정하는 대신 새 이미지 빌드를 권장하는 것 같아서 일반적인 재 빌드 방법이 옳다고 생각하지만 구현의 세부 사항을 개선해야합니다.


빌드 명령과 각 명령의 전체 출력을 포함하여 컨테이너를 빌드하기 위해 취한 정확한 단계를 나열 할 수 있습니까?
BMitch

답변:


140

몇 가지 연구와 테스트를 거친 후 Docker 컨테이너의 수명에 대해 오해가 있음을 발견했습니다. 컨테이너를 다시 시작한다고해서 그 동안 이미지가 다시 빌드되었을 때 Docker가 새 이미지를 사용하게되는 것은 아닙니다. 대신 Docker는 컨테이너 만들기 전에 만 이미지를 가져옵니다 . 따라서 컨테이너를 실행 한 후의 상태는 지속적입니다.

제거가 필요한 이유

따라서 다시 빌드하고 다시 시작하는 것만으로는 충분하지 않습니다. 컨테이너가 서비스처럼 작동한다고 생각했습니다. 서비스를 중지하고 변경 한 다음 다시 시작하면 적용됩니다. 그것은 내 가장 큰 실수였습니다.

컨테이너는 영구적이므로 docker rm <ContainerName>먼저 사용하여 제거해야합니다 . 컨테이너가 제거 된 후에는 docker start. 이것은 docker run새로운 컨테이너 인스턴스를 생성하기 위해 최신 이미지를 사용 하는를 사용하여 수행되어야 합니다.

컨테이너는 가능한 한 독립적이어야합니다.

이 지식이 있으면 컨테이너에 데이터를 저장하는 것이 나쁜 관행으로 인정되는 이유를 이해할 수 있으며 Docker는 대신 데이터 볼륨 / 마운트 호스트 디렉터리 를 권장 합니다 . 애플리케이션을 업데이트하려면 컨테이너를 파괴해야하므로 내부에 저장된 데이터도 손실됩니다. 이로 인해 서비스 종료, 데이터 백업 등에 대한 추가 작업이 발생합니다.

따라서 컨테이너에서 이러한 데이터를 완전히 제외하는 것이 현명한 솔루션입니다. 데이터가 호스트에 안전하게 저장되고 컨테이너가 애플리케이션 자체 만 보유 할 때 데이터에 대해 걱정할 필요가 없습니다.

-rf정말 도움이되지 않는 이유

docker run명령에는라는 정리 스위치가 -rf있습니다. Docker 컨테이너를 영구적으로 유지하는 동작을 중지합니다. 를 사용 -rf하면 Docker는 컨테이너가 종료 된 후이를 파괴합니다. 그러나이 스위치에는 두 가지 문제가 있습니다.

  1. Docker는 또한 컨테이너와 연결된 이름이없는 볼륨을 제거하여 데이터를 죽일 수 있습니다.
  2. 이 옵션을 사용하면 -d스위치를 사용하여 백그라운드에서 컨테이너를 실행할 수 없습니다.

-rf스위치는 빠른 테스트를 위해 개발 중에 작업을 저장하는 좋은 옵션 이지만 프로덕션에는 적합하지 않습니다. 특히 백그라운드에서 컨테이너를 실행하는 옵션이 없기 때문에 대부분 필요합니다.

컨테이너를 제거하는 방법

컨테이너를 간단히 제거하여 이러한 제한을 우회 할 수 있습니다.

docker rm --force <ContainerName>

--force(또는 -f용기에 실행 SIGKILL 사용) 스위치. 대신 다음과 같은 전에 컨테이너를 중지 할 수도 있습니다.

docker stop <ContainerName>
docker rm <ContainerName>

둘 다 동일합니다. SIGTERMdocker stop 도 사용하고 있습니다. 그러나 스위치를 사용 하면 특히 CI 서버를 사용할 때 스크립트가 단축 됩니다. 컨테이너가 실행되고 있지 않으면 오류가 발생합니다. 이로 인해 Jenkins 및 기타 많은 CI 서버가 빌드를 실패한 것으로 잘못 간주합니다. 이 문제를 해결하려면 먼저 질문에서했던 것처럼 컨테이너가 실행 중인지 확인해야합니다 ( 변수 참조 ).--forcedocker stopcontainerRunning

Docker 컨테이너를 다시 빌드하기위한 전체 스크립트

이 새로운 지식에 따르면 다음과 같은 방식으로 스크립트를 수정했습니다.

#!/bin/bash
imageName=xx:my-image
containerName=my-container

docker build -t $imageName -f Dockerfile  .

echo Delete old container...
docker rm -f $containerName

echo Run new container...
docker run -d -p 5000:5000 --name $containerName $imageName

이것은 완벽하게 작동합니다 :)


4
'Docker 컨테이너의 수명에 대해 약간의 오해가 있음을 발견했습니다.'당신은 내 입에서 바로 단어를 꺼 냈습니다. 자세한 설명 감사합니다. 나는 이것을 도커 초보자에게 추천합니다. 이것은 VM과 컨테이너의 차이점을 명확히합니다.
Vince Banzon

2
설명 후, 제가 한 것은 기존 이미지에 무엇을했는지 기록하는 것입니다. 변경 사항을 유지하기 위해 추가하려는 변경 사항이 이미 포함 된 새 이미지를 만드는 새 Dockerfile을 만들었습니다. 이렇게하면 생성 된 새 이미지가 (다소) 업데이트됩니다.
Vince Banzon

--force-recreatedocker 의 옵션이 여기에서 설명하는 것과 유사합니까? 그리고 만약 그렇다면하면, 대신이 솔루션을 사용하는 것이 가치가 없을 것입니다 (죄송합니다 ^^ 그 질문은 바보하지만 난 고정 표시기 멍청한 놈이야 경우)
cglacet

2
@cglacet 예, 비슷하지만 직접 비교할 수는 없습니다. 그러나 docker-compose평범한 docker명령 보다 더 똑똑 합니다. 정기적으로 함께 작업 docker-compose하고 변경 감지가 잘 작동하므로 --force-recreate거의 사용 하지 않습니다. 그냥 docker-compose up --build당신이 (사용자 정의 이미지를 구축 할 때 중요한 build파일 작성의 지침을) 대신 도커 허브를 예에서 이미지를 사용하여.
Lion

35

dockerfile 또는 compose 또는 requirements가 변경 될 때마다 docker-compose up --build. 이미지가 다시 작성되고 새로 고쳐 지도록


1
MySQL 도커 컨테이너를 하나의 서비스로 사용하면 볼륨을 사용한 경우 DB가 비어 /opt/mysql/data:/var/lib/mysql있습니까?
Martin Thoma

나에게 항상 --build로컬 개발 환경에서 사용하는 것에 는 단점이 없습니다 . 도 커가 복사 할 필요가 없다고 가정 할 수있는 파일을 다시 복사하는 속도는 몇 밀리 초 밖에 걸리지 않으며 많은 WTF 순간을 절약 할 수 있습니다.
Danack

1

서비스 이름이 docker-compose 파일에서 호출 한 방법과 일치해야하는 위치 build를 실행하여 특정 서비스를 실행할 수 있습니다 docker-compose up --build <service name>.

docker-compose 파일에 많은 서비스 (.net app-database-let 's encrypt ... 등)가 포함되어 application있고 docker-compose 파일에서 이름이 지정된 .net 앱만 업데이트한다고 가정 합니다. 그런 다음 간단히 실행할 수 있습니다.docker-compose up --build application

추가 매개 변수-d 백그라운드에서 실행하는 것과 같이 명령에 추가 매개 변수를 추가하려는 경우 매개 변수는 서비스 이름 앞에 있어야합니다. docker-compose up --build -d application

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.