【问题标题】:How to update code in a docker container?如何更新 docker 容器中的代码?
【发布时间】:2017-01-29 15:16:13
【问题描述】:

我已经设置了一个 docker django 容器,并使用教程 here 构建了它的镜像。本教程展示了如何制作一个基本的 django 应用程序并将应用程序安装到 "/code",据我了解,它包含在数据卷中。

但是我想了解我将如何更新和开发此代码,并能够发布/部署它。因为当我提交时,它没有考虑代码中的任何更改,因为它是数据量的一部分。

有什么方法可以让 django 代码成为图像的一部分,或者用更新的代码更新图像?

【问题讨论】:

  • 您只需将 Python 源代码添加到安装了适当的 Python 依赖项的容器中。并将该容器的ENTRYPOINT 保留为["python", "/path/to/my.py"]。构建 docker 镜像是你的 CI 系统基于规则完成的事情,比如只在标签上或只来自 master 等等。
  • 如何将源代码添加到容器中而不是数据卷中?
  • 一般工作流程有一个单独的Dockerfile.developmentDockerfile(用于生产)。卷正在开发中,但生产 dockerfile 没有卷指令(在您的情况下不需要)。只需简单地做一个ADD . /code。没有卷。

标签: django docker docker-compose


【解决方案1】:

根据我的经验,Docker 有两个用途:

  1. 能够在容器化环境中开发代码。这非常有用,因为我现在可以在大约 5 分钟内让团队中的新开发人员准备好工作。以前,对于杂项问题,这可能需要一个小时到几个小时,尤其是在旧项目中。
  2. 能够在容器化环境中打包应用程序。这也可以节省大量时间,因为对环境的唯一要求是安装 Docker。

在开发代码时,您应该挂载源/卷,以便您的更改始终反映在容器内。当您想要打包一个应用程序进行部署时,您应该将源代码COPY 放入容器中并适当地打包它。

这是一个 docker-compose 文件,我用于 (1) 构建要开发的映像,(2) 开发我的代码,以及 (3) 发布它(我使用的是 spring boot):

version: '3.7'
services:
  dev:
    image: '${MVN_BUILDER}'
    container_name: '${CONTAINER_NAME}'
    ports:
      - '8080:8080'
    volumes:
      - './src:/build/src'
      - './db:/build/db'
      - './target:/build/target'
      - './logs:/build/logs'
    command: 'mvn spring-boot:run -Drun.jvmArguments="-Xmx512m" -Dmaven.test.skip=true'
  deploy:
    build:
      context: .
      dockerfile: Dockerfile-Deploy
      args:
        MVN_BUILDER: '${MVN_BUILDER}'
    image: '${DEPLOYMENT_IMAGE}'
    container_name: '${CONTAINER_NAME}'
    ports:
      - '8080:8080'
  maven:
    build:
      context: .
      dockerfile: Dockerfile
    image: '${MVN_BUILDER}'
    container_name: '${CONTAINER_NAME}'
  1. 我会运行docker-compose build maven 来构建我的基础镜像。这是必需的,以便当我在容器中运行我的代码时,所有依赖项都安装在映像中。用于此的 Dockerfile 基本上复制到 pom.xml 到映像中并下载应用程序所需的依赖项。请注意,只要依赖项发生变化,就需要执行此操作。这是用于构建 maven 服务中引用的映像的 Dockerfile:
### BUILD a maven builder. This will contain all mvn dependencies and act as an abstraction for all mvn goals
FROM maven:3.5.4-jdk-8-alpine as builder

#Copy Custom Maven settings
#COPY settings.xml /root/.m2/

# create app folder for sources
RUN mkdir -p /build
RUN mkdir -p /build/logs

# The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile.
WORKDIR /build
COPY pom.xml /build
#Download all required dependencies into one layer
RUN mvn -B dependency:go-offline dependency:resolve-plugins
RUN mvn clean install
  1. 接下来,我将运行docker-compose up dev 来启动我的dev 服务并开始开发我的应用程序。该服务将我的代码挂载到容器中,并使用 Maven 启动 Spring Boot 应用程序。每当我更改代码时,spring boot 都会重新启动服务器并反映我的更改。

  2. 最后,一旦我对我的应用程序感到满意,我就会构建一个映像,该映像将我的应用程序打包以使用 docker-compose build deploy 进行部署。我使用两阶段构建过程首先将源代码复制到容器中并将其打包为Jar 进行部署,然后将Jar 放入第二阶段,我可以简单地运行java -jar build/app.jar(在容器中)启动我的应用程序并删除第一阶段。而已!现在,您可以在安装了 Docker 的任何地方部署此最新映像。

这是最后一个 Dockerfile (Dockerfile-Deploy) 的样子:

ARG MVN_BUILDER
### Stage 1 - BUILD image
FROM $MVN_BUILDER as builder
COPY src /build/src
RUN mvn clean package -PLOCAL

### Stage 2 - Deploy Jar
FROM openjdk:8
RUN mkdir -p /build
COPY --from=builder /build/target/*.jar /build/app.jar
EXPOSE 8080  
ENTRYPOINT ["java","-jar","build/app.jar"] 

这里的.env 文件与docker-compose 文件位于同一目录中。我用它来抽象图像/容器名称,并在需要新图像时简单地在一个地方增加版本号。

MVN_BUILDER=some/maven/builder:0.1
DEPLOYMENT_IMAGE=some/deployment/spring:0.1
CONTAINER_NAME=spring-container
CONTAINER_NAME_DEBUG=spring-container-debug

【讨论】:

    【解决方案2】:

    我认为现在回答您的问题为时已晚,但是,这可能对其他伸出援手的人有益。

    你提到的教程对于初学者来说有点棘手,所以我稍微改变了结构。我假设您有一个 docker 注册表帐户(如 Dockerhub),用于将图像发布到。如果您想访问远程主机上的图像,这是必需的(您可以复制实际的图像文件,但不推荐)。

    创建项目

    假设您要使用 Django 创建一个网站并将其 dockerize,首先,您这样做:

    django-admin startproject samplesite
    

    它会创建一个目录samplesite,其中包括以下内容(我添加了 requirements.txt):

    db.sqlite3  manage.py  requirements.txt  samplesite
    

    添加 Dockerfile 和 docker-compose.yml

    如您所见,DockerfileDockerfile 相比没有任何变化。

    FROM python:3
    ENV PYTHONUNBUFFERED 1
    RUN mkdir /code
    WORKDIR /code
    COPY requirements.txt /code/
    RUN pip install -r requirements.txt
    COPY . /code/
    

    但是对于docker-compose.yml

    version: '3'
    
    services:
      db:
        image: postgres
      web:
        build: .
        image: yourUserNameOnDockerHub/mywebsite:0.1  # this line is added
        command: python manage.py runserver 0.0.0.0:8000
        #volumes:
        #  - .:/code
        ports:
          - "8000:8000"
        depends_on:
          - db
    

    docker-compose.yml 也与教程中提到的几乎相同,只是注释了卷并添加了一行image: mywebsite:0.1。该行允许我们跟踪构建的映像并在需要时部署它。卷挂载与您编写的代码无关,被放在那里是为了取出被 Django 更改的动态内容(sqlite、上传的文件等)。

    构建并运行

    如果您第一次运行docker-compose up 一切正常,但是,由于添加了新行,当您在第一次之后更改代码时,更改不会反映在运行的容器中。这是因为在每个docker-compose up 上,compose 都会查找mywebsite:0.1(已经存在)并且不会构建新图像并基于旧图像创建容器。由于我们需要该图像名称和标签来发布/部署我们的图像,我们需要改为使用:

    docker-compose up --build
    

    它将重新构建反映更改的图像。每次进行一些更改,运行它并创建一个可以看到的新图像(请注意,虽然名称和标签保持不变,但图像 id 的更改表明这是一个新图像):

    $ docker images
    REPOSITORY                                   TAG                 IMAGE ID            CREATED             SIZE
    yourUserNameOnDockerHub/mywebsite            0.1                 033c9d2bfac0        7 seconds ago       974MB
    

    发布和部署

    如果您在 Dockerhub(或任何其他注册表)上设置了一个帐户,您可以发布该映像以供以后使用或部署在远程服务器上:

    docker push yourUserNameOnDockerHub/mywebsite:01 
    

    如果你想在远程主机上部署它并想再次使用 docker-compose,只需将 docker-compose.yml 更改为:

    version: '3'
    
    services:
      db:
        image: postgres
      web:
        image: yourUserNameOnDockerHub/mywebsite:0.1 
        command: python manage.py runserver 0.0.0.0:8000
        #volumes:
        #  - .:/code
        ports:
          - "8000:8000"
        depends_on:
          - db
    

    请注意,build: . 行已被删除(因为我们将只运行它)。在本地开发时,每当您运行docker-compose up --build 时,都会创建并标记一个新图像,并且基于该图像的容器将在撰写堆栈中运行。如果您认为自己对更改感到满意,请按照发布步骤使其在服务器上生效。

    【讨论】:

      【解决方案3】:

      当您想更新图像时,假设由于您的应用程序代码更改,您在图像构建期间使用COPY,因此在Dockerfile 中您可以执行类似的操作

      COPY /you/code/on/the/host /var/www
      

      另请参阅我关于“卷”和图像构建https://stackoverflow.com/a/39314602/3625317 的回答,以阐明构建中缺少代码的原因

      【讨论】:

        【解决方案4】:

        tutorial 的第 9 步中,您设置了一个音量。此卷将链接您的当前目录和您的容器/code 目录。换句话说,它们将是相同的。

        因此,对本地文件的任何更新也会更改容器中的文件。请记住,您需要重新启动应用才能进行更改。

        在部署映像之前,您需要创建第二个 docker compose 文件。此文件将删除卷,因此代码将保留在容器内并且不会从外部更改。您可以按照docker compose documentation中提供的步骤进行操作。

        【讨论】:

        • 当我更改 /code 中的文件时,它们会显示在本地 Web 应用程序中,但是当我推送容器映像并部署它时,它不包含更改。
        • 我认为音量选项可能是问题所在。当您推送您的容器并运行它时,该卷仍然可以工作,但不再适用于您的本地文件。请务必更新您正在部署的代码。另一种选择是删除卷。这样,您每次更新代码时都需要重建映像。
        • 这就是我要问的。如何更新我正在部署的代码?
        • 您要部署到哪里?虚拟主机?云?
        • 部署时您需要做的第一件事是删除应用程序代码的所有卷绑定,以便代码保留在容器内并且不能从外部更改 .您可以按照此docker compose documentation 进行操作。我会据此更新我的答案。
        猜你喜欢
        • 1970-01-01
        • 2015-02-16
        • 1970-01-01
        • 1970-01-01
        • 2021-12-17
        • 2023-02-25
        • 1970-01-01
        • 1970-01-01
        • 2015-03-19
        相关资源
        最近更新 更多