애플리케이션을 컨테이너화할 때 런타임에 필요하지 않은 파일(예: 빌드타임 종속 항목 및 중간 파일)이 실수로 컨테이너 이미지에 포함될 수 있습니다. 이러한 불필요한 파일로 인해 컨테이너 이미지 크기가 커져 이미지가 Docker 레지스트리와 컨테이너 런타임 사이를 이동할 때 시간과 비용이 추가로 발생할 수 있습니다.
컨테이너 이미지 크기를 줄이려면 애플리케이션 빌드 단계를 애플리케이션을 빌드하는 데 사용되는 도구와 함께 런타임 컨테이너 어셈블리 단계에서 분리하세요.
Cloud Build는 일련의 Docker 컨테이너에 Git, Docker, Google Cloud CLI와 같은 일반적인 개발자 도구를 제공합니다. 이러한 도구를 사용하여 애플리케이션을 빌드하는 단계와 최종 런타임 환경을 어셈블하는 단계를 구분하여 빌드 구성 파일을 정의하세요.
예를 들어 소스 코드, 애플리케이션 라이브러리, 빌드 시스템, 빌드 시스템 종속 항목, JDK와 같은 파일이 필요한 자바 애플리케이션을 빌드하는 경우 다음과 같은 Dockerfile이 있을 수 있습니다.
FROM java:8
COPY . workdir/
WORKDIR workdir
RUN GRADLE_USER_HOME=cache ./gradlew buildDeb -x test
RUN dpkg -i ./gate-web/build/distributions/*.deb
CMD ["/opt/gate/bin/gate"]
위의 예시에서 패키지를 만드는 데 사용되는 Gradle은 작동에 필요한 여러 라이브러리를 다운로드합니다. 이러한 라이브러리는 패키지 빌드에 필수적이지만 런타임에는 필요하지 않습니다. 모든 런타임 종속 항목은 패키지에 번들로 제공됩니다.
Dockerfile의 각 명령어는 컨테이너에 새 레이어를 만듭니다. 데이터가 해당 레이어에서 생성되고 동일한 명령어에서 삭제되지 않으면 해당 공간을 복구할 수 없습니다. 여기에서 Gradle은 빌드를 수행하기 위해 수백 MB의 라이브러리를 cache 디렉터리에 다운로드하지만 라이브러리가 삭제되지 않습니다.
빌드를 수행하는 보다 효율적인 방법은 Cloud Build를 사용하여 애플리케이션 빌드와 런타임 레이어 빌드를 구분하는 것입니다.
다음 예에서는 자바 애플리케이션을 빌드하는 단계와 런타임 컨테이너를 어셈블하는 단계를 구분합니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-09-04(UTC)"],[[["\u003cp\u003eBuilding leaner Docker images involves separating the application build process from the assembly of the runtime environment.\u003c/p\u003e\n"],["\u003cp\u003eUnnecessary files, such as build-time dependencies and intermediate files, can bloat container image sizes, adding extra time and cost.\u003c/p\u003e\n"],["\u003cp\u003eCloud Build can be used to define separate steps for building the application and assembling its runtime environment, leveraging tools like Git, Docker, and the Google Cloud CLI.\u003c/p\u003e\n"],["\u003cp\u003eUsing a separate, lean base layer like Alpine Linux (e.g., \u003ccode\u003eopenjdk:8u111-jre-alpine\u003c/code\u003e) in a \u003ccode\u003eDockerfile.slim\u003c/code\u003e can significantly reduce the final image size by only using the JRE instead of the JDK.\u003c/p\u003e\n"],["\u003cp\u003eThe \u003ccode\u003ecloudbuild.yaml\u003c/code\u003e or \u003ccode\u003ecloudbuild.json\u003c/code\u003e files define the build steps to build and assemble the runtime container, using a separate \u003ccode\u003eDockerfile.slim\u003c/code\u003e and creating the final Docker image.\u003c/p\u003e\n"]]],[],null,["# Building leaner containers\n\nThis page describes how to build leaner Docker images.\n\nBuilding leaner containers\n--------------------------\n\nWhen you containerize an application, files that are not needed at runtime, such\nas build-time dependencies and intermediate files, can be inadvertently included\nin the container image. These unneeded files can increase the size of the\ncontainer image and thus add extra time and cost as the image moves between your\nDocker registry and your container runtime.\n\nTo help reduce the size of your container image, separate the building of the\napplication, along with the tools used to build it, from the assembly of the\nruntime container.\n\nCloud Build provides a [series of Docker\ncontainers](https://github.com/GoogleCloudPlatform/cloud-builders) with common\ndeveloper tools such as Git, Docker, and the Google Cloud CLI. Use\nthese tools to define a build config file with one step to build the\napplication, and another step to assemble its final runtime environment.\n\nFor example, if you're building a Java application, which requires files such as\nthe source code, application libraries, build systems, build system\ndependencies, and the JDK, you might have a Dockerfile that looks like the\nfollowing: \n\n FROM java:8\n\n COPY . workdir/\n\n WORKDIR workdir\n\n RUN GRADLE_USER_HOME=cache ./gradlew buildDeb -x test\n\n RUN dpkg -i ./gate-web/build/distributions/*.deb\n\n CMD [\"/opt/gate/bin/gate\"]\n\nIn the above example, Gradle, which is used to build the package, downloads a\nlarge number of libraries in order to function. These libraries are essential to\nthe building of the package, but are not needed at runtime. All of the runtime\ndependencies are bundled up in the package.\n\nEach command in the `Dockerfile` creates a new layer in the container. If data\nis generated in that layer and is not deleted in the same command, that space\ncannot be recovered. In this case Gradle is downloading hundreds of megabytes of\nlibraries to the `cache` directory in order to perform the build, but the\nlibraries are not deleted.\n\nA more efficient way to perform the build is to use Cloud Build to\nseparate building the application from building its runtime layer.\n\nThe following example separates the step for building the Java application from\nthe step for assembling the runtime container: \n\n### YAML\n\n1. **Build the application** : In `cloudbuild.yaml`, add\n a step to build the application.\n\n The following code adds a step that builds the `java:8` image,\n which contains the Java code. \n\n ```\n steps:\n\n - name: 'java:8'\n env: ['GRADLE_USER_HOME=cache']\n entrypoint: 'bash'\n args: ['-c', './gradlew gate-web:installDist -x test']\n\n ```\n2. **Assemble the runtime container** : In `cloudbuild.yaml`, add a step to assemble the runtime container.\n\n \u003cbr /\u003e\n\n The following code adds a step named\n `gcr.io/cloud-builders/docker` that assembles the runtime\n container. It defines the runtime container in a separate file named\n `Dockerfile.slim`.\n\n The example uses the Alpine Linux base layer\n `openjdk:8u111-jre-alpine`, which is incredibly lean. Also, it\n includes the JRE, instead of the bulkier JDK that was necessary to build the\n application. \n\n ```\n cloudbuild.yaml\n\n steps:\n - name: 'java:8'\n env: ['GRADLE_USER_HOME=cache']\n entrypoint: 'bash'\n args: ['-c',\n './gradlew gate-web:installDist -x test']\n\n - name: 'gcr.io/cloud-builders/docker'\n args: ['build',\n '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA',\n '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest',\n '-f', 'Dockerfile.slim',\n '.'\n ]\n\n\n Dockerfile.slim\n\n FROM openjdk:8-jre-alpine\n\n COPY ./gate-web/build/install/gate /opt/gate\n\n CMD [\"/opt/gate/bin/gate\"]\n ```\n3. **Create the Docker images** : In `cloudbuild.yaml`, add a step to create the images. \n\n ```\n steps:\n - name: 'java:8'\n env: ['GRADLE_USER_HOME=cache']\n entrypoint: 'bash'\n args: ['-c', './gradlew gate-web:installDist -x test']\n - name: 'gcr.io/cloud-builders/docker'\n args: ['build',\n '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA',\n '-t', 'gcr.io/$PROJECT_ID/$REPO_NAME:latest',\n '-f', 'Dockerfile.slim', '.']\n images:\n - 'gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA'\n - 'gcr.io/$PROJECT_ID/$REPO_NAME:latest'\n ```\n\n### JSON\n\n1. **Build the application** : In `cloudbuild.json`, add a step to\n build the application.\n\n The following code adds a step named `java:8` for\n building the Java code. \n\n ```\n {\n \"steps\": [\n {\n \"name\": \"java:8\",\n \"env\": [\n \"GRADLE_USER_HOME=cache\"\n ],\n \"entrypoint\": \"bash\",\n \"args\": [\n \"-c\",\n \"./gradlew gate-web:installDist -x test\"\n ]\n },\n }\n ```\n2. **Assemble the runtime container** : In `cloudbuild.json`, add a\n step to assemble the runtime container.\n\n The following code adds a step named\n `gcr.io/cloud-builders/docker` that assembles the runtime\n container. It defines the runtime container in a separate file named\n `Dockerfile.slim`.\n\n The example uses the Alpine Linux base layer\n `openjdk:8u111-jre-alpine`, which is incredibly lean. Also, it\n includes the JRE, instead of the bulkier JDK that was necessary to build the\n application. \n\n ```\n cloudbuild.json:\n\n {\n \"steps\": [\n {\n \"name\": \"java:8\",\n \"env\": [\n \"GRADLE_USER_HOME=cache\"\n ],\n \"entrypoint\": \"bash\",\n \"args\": [\n \"-c\",\n \"./gradlew gate-web:installDist -x test\"\n ]\n },\n {\n \"name\": \"gcr.io/cloud-builders/docker\",\n \"args\": [\n \"build\",\n \"-t\",\n \"gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA\",\n \"-t\",\n \"gcr.io/$PROJECT_ID/$REPO_NAME:latest\",\n \"-f\",\n \"Dockerfile.slim\",\n \".\"\n ]\n }\n ],\n }\n\n Dockerfile.slim:\n\n FROM openjdk:8u111-jre-alpine\n\n COPY ./gate-web/build/install/gate /opt/gate\n\n CMD [\"/opt/gate/bin/gate\"]\n ```\n3. **Create the Docker images** : In `cloudbuild.json`, add a step to create the images. \n\n ```\n {\n \"steps\": [\n {\n \"name\": \"java:8\",\n \"env\": [\n \"GRADLE_USER_HOME=cache\"\n ],\n \"entrypoint\": \"bash\",\n \"args\": [\n \"-c\",\n \"./gradlew gate-web:installDist -x test\"\n ]\n },\n {\n \"name\": \"gcr.io/cloud-builders/docker\",\n \"args\": [\n \"build\",\n \"-t\",\n \"gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA\",\n \"-t\",\n \"gcr.io/$PROJECT_ID/$REPO_NAME:latest\",\n \"-f\",\n \"Dockerfile.slim\",\n \".\"\n ]\n }\n ],\n \"images\": [\n \"gcr.io/$PROJECT_ID/$REPO_NAME:$COMMIT_SHA\",\n \"gcr.io/$PROJECT_ID/$REPO_NAME:latest\"\n ]\n }\n ```"]]