首页 > 解决方案 > 如何在没有 from 标志的情况下编写多阶段 Dockerfile

问题描述

这实际上是我今天提出的这个问题的延续。

--from我有一个使用标志的多阶段 Dockerfile :

FROM docker.m.our-intra.net/microsoft/dotnet:2.1-sdk
WORKDIR /app
COPY . ./aspnetapp/
WORKDIR /app/aspnetapp
RUN dotnet publish -c Release -o out

FROM docker.m.our-intra.net/microsoft/dotnet:2.1.4-aspnetcore-runtime
WORKDIR /app
COPY --from=docker.m.our-intra.net/microsoft/dotnet:2.1-sdk /app/aspnetapp/MyProject.WebApi/out ./
ENTRYPOINT ["dotnet", "MyProject.WebApi.dll"]

在这个文件的帮助下,我能够成功地在本地构建图像。

但是我不能在我的 Jenkins 管道中使用这个 Dockerfile,因为 Jenkins 服务器引擎低于 17.05 版本并且不会更新(可能稍后但不是现在)。

我是 Docker 和 Jenkins 的新手。如果有人可以帮助我修改 Dockerfile 以便我可以在没有--from标志的情况下使用它,我将不胜感激。

更新:

楼上说的Dockerfile不对。Dockerfile借助我在本地计算机上成功构建映像并成功运行应用程序的工作版本如下:

FROM docker.m.our-intra.net/microsoft/dotnet:2.1-sdk AS build
WORKDIR /app
COPY . ./aspnetapp/
WORKDIR /app/aspnetapp
RUN dotnet publish -c Release -o out

FROM docker.m.our-intra.net/microsoft/dotnet:2.1.4-aspnetcore-runtime AS runtime
WORKDIR /app
COPY --from=build /app/aspnetapp/MyProject.WebApi/out ./
ENTRYPOINT ["dotnet", "MyProject.WebApi.dll"]

更新 2:

我正在尝试遵循 Carlos 的建议,现在我有两个 docker 文件。

这是我的Docker-build

FROM docker.m.our-intra.net/microsoft/dotnet:2.1-sdk
WORKDIR /app
COPY . ./aspnetapp/
WORKDIR /app/aspnetapp
RUN dotnet publish -c Release -o out

这是我的Dockerfile

FROM docker.m.our-intra.net/microsoft/dotnet:2.1.4-aspnetcore-runtime
COPY . .
ENTRYPOINT ["dotnet", "MyProject.WebApi.dll"]

这是我的Jenkinsfile

def docker_repository_url = 'docker.m.our-intra.net'
def artifact_group = 'some-artifact-group'                  
def artifact_name = 'my-service-api'

pipeline {
    agent {
        label 'build'
    }
    stages {
        stage('Checkout') {
            steps {
                script {
                    echo 'Checkout...'
                    checkout scm
                    echo 'Checkout Completed'
                }
            }
        }
        stage('Build') {
            steps {
                script {
                    echo 'Build...'
                    sh 'docker version'
                    sh 'docker build -t fact:v${BUILD_NUMBER} -f Dockerfile-build .'
                    echo 'Build Completed'
                }               
            }
        }
        stage('Extract artifact') {
            steps {
                script {
                    echo 'Extract...'
                    sh 'docker create --name build-stage-container fact:v${BUILD_NUMBER}'
                    sh 'docker cp build-stage-container:/app/aspnetapp/MyProject.WebApi/out .'
                    sh 'docker rm -f build-stage-container'
                    echo 'Extract Completed'
                }               
            }
        }
        stage('Copy compiled artifact') {
            steps {
                script {
                    echo 'Copy artifact...'
                    sh "docker build -t ${docker_repository_url}/${artifact_group}/${artifact_name}:v${BUILD_NUMBER} -f Dockerfile ."
                    echo 'Copy artifact Completed'
                }               
            }
        }
        stage('Push image') {
            steps {
                script {                                                    
                    withCredentials([[
                        $class: 'UsernamePasswordMultiBinding', 
                        credentialsId: 'jenkins',
                        usernameVariable: 'USERNAME', 
                        passwordVariable: 'PASSWORD'
                    ]]) {
                            def username = env.USERNAME
                            def password = env.PASSWORD

                            echo 'Login...'
                            sh "docker login ${docker_repository_url} -u ${username} -p ${password}"
                            echo 'Login Successful' 

                            echo 'Push image...'
                            sh "docker push ${docker_repository_url}/${artifact_group}/${artifact_name}:v${BUILD_NUMBER}"   
                            echo 'Push image Completed'
                    }                               
                }               
            }
        }
    }
}

所有步骤都成功了,但是当我尝试在本地运行图像(从 Maven 中提取它之后)或在 OpehShift 集群上运行它时失败并说:

您的意思是运行 dotnet SDK 命令吗?请从以下位置安装 dotnet SDK:http: //go.microsoft.com/fwlink/ ?LinkID=798306&clcid=0x409

我究竟做错了什么?

标签: dockerjenkinsjenkins-pipelinedockerfile

解决方案


TL;DR:您需要自己复制底层功能,在 Docker 之外

首先,您使用的--from选项错误。要从之前的构建阶段复制,您必须引用其索引或名称,例如:

FROM docker.m.our-intra.net/microsoft/dotnet:2.1-sdk
...

FROM docker.m.our-intra.net/microsoft/dotnet:2.1.4-aspnetcore-runtime
COPY --from=0 /app/aspnetapp/MyProject.WebApi/out ./

或者

FROM docker.m.our-intra.net/microsoft/dotnet:2.1-sdk AS build-stage
...
FROM docker.m.our-intra.net/microsoft/dotnet:2.1.4-aspnetcore-runtime
COPY --from=build-stage /app/aspnetapp/MyProject.WebApi/out ./

使用您当前的 Dockerfile,它会尝试从上游 docker 映像复制文件,而不是从之前的构建阶段。

其次,您不能使用 17.05 之前的版本进行多阶段 Docker 构建。您需要在 Docker 之外自己复制底层功能。

为此,您可以使用一个 Dockerfile 来构建您的工件并基于该映像运行一个一次性容器,从中提取工件。你不需要运行容器,你可以简单地创建它docker create(这将创建可写容器层):

docker create --name build-stage-container build-stage-image
docker cp build-stage-container:/app/aspnetapp/MyProject.WebApi/out .

然后,您可以使用第二个 Dockerfile 来构建镜像,复制从前一阶段提取的工件,并使用COPY构建上下文中的简单内容。


推荐阅读