code

파일 변경 시 도커 컨테이너 재구축

starcafe 2023. 11. 4. 13:12
반응형

파일 변경 시 도커 컨테이너 재구축

ASP를 실행하는 경우.NET Core application, 나는 Git이 Jenkins를 이용하여 가져온 어플리케이션을 빌드하고 컨테이너에 소스 코드를 복사하는 도커 파일을 생성했습니다.작업 공간에서는 도커 파일에서 다음 작업을 수행합니다.

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또한 새 컨테이너가 제작되기 전에 컨테이너를 정지/removing합니다.제가 여기서 뭘 잘못하고 있는지 모르겠어요.도커가 이미지를 올바르게 업데이트하고 있는 것 같습니다.COPY src src계층 ID를 생성하고 캐시 호출을 수행하지 않습니다.

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

용기를 업데이트하는 권장 방법은 무엇입니까?

일반적인 시나리오는 다음과 같습니다.응용프로그램이 도커 컨테이너의 서버에서 실행되고 있습니다.이제 파일을 수정하는 등 앱의 일부가 업데이트됩니다.이제 컨테이너에서 새 버전을 실행해야 합니다.도커는 기존 컨테이너를 수정하는 대신 새로운 이미지를 구축하는 것을 권장하는 것 같아 저처럼 리빌딩하는 일반적인 방법이 맞다고 생각하지만, 구현에 있어 몇 가지 세부 사항은 개선되어야 합니다.

영상설명 영상 (2022년부터)

Visual video explanation container vs images

저의 첫 번째 시각적 설명에 대해 긍정적인 피드백을 많이 받았기 때문에 그래픽 비디오에서 더 잘 시각화할 수 있는 것들이 있기 때문에 이 질문과 답변을 위해 또 다른 영상을 만들기로 결정했습니다.여러 시스템(및 K8s)에서 도커를 사용하여 지난 몇 년 동안 얻은 지식과 경험을 바탕으로 이 답변을 시각화하고 업데이트합니다.

이 질문은 ASP의 맥락에서 제기된 것입니다.NET Core, 이 프레임워크와 실제로는 관련이 없습니다.문제는 도커 개념에 대한 기본적인 이해가 부족했기 때문에 거의 모든 애플리케이션과 프레임워크에서 발생할 수 있습니다.그런 이유로 저는 여러분들 중 많은 분들이 웹 서버에 익숙하실 것이라 생각하기 때문에 간단한 Nginx 웹 서버를 사용했습니다. 하지만 모든 분들이 ASP와 같은 구체적인 프레임워크가 어떻게 작동하는지 알지는 못합니다.NET Core가 작동합니다.

이 비디오의 기본 주제인 컨테이너 대 이미지의 차이와 라이프사이클의 차이를 이해하는 것이 근본적인 문제입니다.

문자 답변 (본래 2016년)

몇 번의 조사와 테스트를 거쳐 도커 컨테이너의 수명에 대해 오해를 하고 있다는 것을 알게 되었습니다.컨테이너를 다시 시작하는 것만으로 도커는 이미지를 재구성할 때 새 이미지를 사용하지 않습니다.대신 Docker는 컨테이너를 만들기 에만 이미지를 가져옵니다.따라서 컨테이너를 실행한 후의 상태는 지속됩니다.

탈거가 필요한 이유

따라서 재구축하고 다시 시작하는 것으로는 충분하지 않습니다.저는 컨테이너가 서비스처럼 작동한다고 생각했습니다.서비스를 중지하고 변경한 후 다시 시작하면 적용됩니다.그것이 제 가장 큰 실수였습니다.

용기는 영구적이기 때문에 다음을 사용하여 제거해야 합니다.docker rm <ContainerName>첫째. 용기를 제거한 후에는 단순히 다음과 같은 방법으로 시작할 수 없습니다.docker start. 이 작업은 다음을 사용하여 수행해야 합니다.docker run, 새 컨테이너 인스턴스를 만들기 위해 최신 이미지를 사용합니다.

용기는 가능한 한 독립적이어야 함

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

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

왜죠-rf별로 도움이 되지 않을 수도 있습니다.

docker runcommand, clean up 스위치가 있습니다.-rf. 도커 컨테이너를 영구적으로 보관하는 행위를 중지합니다.사용.-rf, 컨테이너가 빠져나간 후 도커가 컨테이너를 파괴합니다.하지만 이 스위치에 문제가 있습니다.도커는 또한 컨테이너와 연관된 이름 없이 볼륨을 제거하므로 데이터가 삭제될 수 있습니다.

그 동안에-rf스위치는 빠른 테스트를 위해 개발 중에 작업을 절약할 수 있는 좋은 옵션이며 생산에 적합하지 않습니다.특히 컨테이너를 백그라운드에서 실행할 수 있는 옵션이 없기 때문에 대부분 필요합니다.

용기를 분리하는 방법

컨테이너를 제거하기만 하면 다음과 같은 제한을 피할 수 있습니다.

docker rm --force <ContainerName>

--force(또는-f) 실행 중인 컨테이너에 SIGKILL을 사용하는 스위치입니다.대신 다음 작업 전에 컨테이너를 중지할 수도 있습니다.

docker stop <ContainerName>
docker rm <ContainerName>

둘 다 같습니다.docker stopSIGTERM을 사용하기도 합니다. 하지만.--forceswitch는 특히 CI 서버를 사용할 때 스크립트를 단축합니다.docker stop컨테이너가 실행되고 있지 않으면 오류를 발생시킵니다.이로 인해 Jenkins와 다른 많은 CI 서버가 빌드를 실패한 것으로 잘못 간주하게 됩니다.이 문제를 해결하기 위해서는 먼저 문제의 경우처럼 컨테이너가 작동하는지 확인해야 합니다(참조).containerRunning변수).

더 좋은 방법이 있습니다 (2016년 추가)

일반 도커 명령은 다음과 같습니다.docker build,docker run다른 것들은 초보자들이 기본 개념을 이해하는 데 좋은 방법입니다. 이미 도커에 익숙하고 생산적이 되고 싶을 때는 짜증이 납니다.더 좋은 방법은 도커 컴포지트를 사용하는 것입니다.다중 컨테이너 환경을 위해 설계되었지만 단일 컨테이너로 독립 실행형을 사용할 경우에도 이점이 있습니다.다중 컨테이너 환경이 실제로 드물지는 않지만 말입니다.거의 모든 애플리케이션은 적어도 애플리케이션 서버와 일부 데이터베이스를 가지고 있습니다.일부는 서버, cron 컨테이너 또는 다른 것들을 캐싱하는 것을 훨씬 더 좋아합니다.

version: "2.4"
services:
  my-container:
    build: .
    ports:
      - "5000:5000"

이제 그냥 사용해도 됩니다.docker-compose up --build그리고 제가 수작업으로 했던 모든 과정을 작곡가가 알아서 할 겁니다.2016년부터 답변으로 추가한 평이한 Docker 명령어가 있는 스크립트보다 이것이 더 좋습니다.여전히 작동하지만 더 복잡하며 특정 상황을 도커 컴포지트처럼 잘 처리하지 못합니다.예를 들어, 모든 것이 최신 상태인지 확인하고 변경 사항으로 인해 재구성해야 하는 항목만 재구성하는지 확인합니다.

특히 여러 개의 컨테이너를 사용하는 경우, composition을 사용하면 훨씬 더 많은 이점을 얻을 수 있습니다.예를 들어 수동으로 네트워크를 생성/유지 관리해야 하는 컨테이너를 연결하는 것입니다.또한 데이터베이스 컨테이너가 시작할 때 DB에 의존하는 응용프로그램 서버보다 먼저 시작되도록 종속성을 지정할 수도 있습니다.

과거에 Docker-Compose 1.x에서는 특히 캐싱과 관련된 몇 가지 문제를 발견했습니다.따라서 내용이 변경된 경우에도 컨테이너가 업데이트되지 않습니다.저는 한동안 그런 문제들을 다시 보지 못하고 composing v2를 테스트해 보았는데, 지금은 수정된 것 같습니다.

도커 컨테이너 재구축 전체 스크립트 (2016년 당초 답변)

이 새로운 지식에 따라 저는 대본을 다음과 같은 방법으로 고쳤습니다.

#!/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

완벽하게 작동합니다 :)

도커 파일이나 구성 또는 요구 사항이 변경될 때마다 다음을 사용하여 다시 실행합니다.docker-compose up --build. 이미지를 재구축하고 새로 고침

뛸 수 있습니다build실행하여 특정 서비스를 위해docker-compose up --build <service name>서비스 이름이 일치해야 하는 경우 도커 compose 파일에서 어떻게 이름을 불렀습니까?

: 도커로 작성된 파일에 많은 서비스(.net app - database - encrypt...)가 포함되어 있다고 가정합니다.등) 그리고 당신은 다음과 같은 이름을 가진 .net 앱만 업데이트하기를 원합니다.application도커 compose 파일에 저장되어 있습니다.그러면 간단히 실행할 수 있습니다.docker-compose up --build application

추가 파라미터 명령에 다음과 같은 추가 파라미터를 추가하고자 할 경우-d백그라운드에서 실행하려면 매개 변수가 서비스 이름 앞에 있어야 합니다.docker-compose up --build -d application

전체 재구축을 수행하는 대신 복사본만으로 재구축을 수행할 수 있습니다.

와 비슷한 선을 더하다

RUN mkdir -p /BUILD_TOKEN/f7e0188ea2c8466ebf77bf37eb6ab1c1
COPY src src

mkdir call은 부분 재구축이 필요할 때마다 변경할 토큰을 포함하는 도커가 실행해야 하는 라인을 가지는 것입니다.

이제 복사본을 강제로 복사해야 할 때마다 빌드 스크립트가 uuid를 대체하도록 하십시오.

다트에서 나는 합니다.


  if (parsed['clone'] as bool == true) {
    final uuid = const Uuid().v4().replaceAll('-', '');

    replace(dockerfilePath, RegExp('RUN mkdir -p /BUILD_TOKEN/.*'),
        'RUN mkdir -p /BUILD_TOKEN/$uuid');
  }

그런 다음 빌드 도구를 다음과 같이 실행합니다.

build.dart --clone

이것은 제 전체 다트 대본입니다. 하지만 약간의 관련없는 부분들이 있습니다.

#! /usr/bin/env dcli

import 'dart:io';

import 'package:dcli/dcli.dart';
import 'package:mongo_dart/mongo_dart.dart';
import 'package:unpubd/src/version/version.g.dart';

/// build and publish the unpubd docker container.
void main(List<String> args) {
  final parser = ArgParser()
    ..addFlag('clean',
        abbr: 'c', help: 'Force a full rebuild of the docker container')
    ..addFlag('clone', abbr: 'l', help: 'Force reclone of the git repo.');

  ArgResults parsed;
  try {
    parsed = parser.parse(args);
  } on FormatException catch (e) {
    print(e);
    print(parser.usage);
    exit(1);
  }
  final dockerfilePath =
      join(DartProject.self.pathToProjectRoot, 'resources', 'Dockerfile');

  'dcli pack'.run;

  print(blue('Building unpubd $packageVersion'));

  final tag = 'noojee/unpubd:$packageVersion';
  const latest = 'noojee/unpubd:latest';

  var clean = '';
  if (parsed['clean'] as bool == true) {
    clean = ' --no-cache';
  }

  if (parsed['clone'] as bool == true) {
    final uuid = const Uuid().v4().replaceAll('-', '');
    replace(dockerfilePath, RegExp('RUN mkdir -p /BUILD_TOKEN/.*'),
        'RUN mkdir -p /BUILD_TOKEN/$uuid');
  }

  'docker  build $clean -t $tag -t $latest -f $dockerfilePath .'.run;

  'docker push noojee/unpubd:$packageVersion'.run;
  'docker push $tag'.run;
  'docker push $latest'.run;
}

언급URL : https://stackoverflow.com/questions/41322541/rebuild-docker-container-on-file-changes

반응형