Как написать многоступенчатый Dockerfile без флагов - PullRequest
0 голосов
/ 10 декабря 2018

Это на самом деле продолжение этого вопроса , который я задал сегодня.

У меня есть многоэтапный Dockerfile, использующий флаг --from:

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"]

С помощью этого файла я могу успешно создать образ локально.

НО Я не могу использовать этот Dockerfile в моем конвейере Jenkins, потому что ядро ​​Jenkins Server меньше 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:

Я пытаюсь последовать совету Карлоса, и теперь у меня есть два файла докера.

Это мой 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

Что я делаю не так?

Ответы [ 3 ]

0 голосов
/ 11 декабря 2018

@ Ответ Карлоса совершенно действителен.Однако, поскольку вы используете jenkins и конвейеры, вы можете быть довольны следующим альтернативным решением:

Если вы используете jenkins с динамическим предоставлением pod в дистрибутиве kubernetes, вы можете сделать следующее:

  • Используйте pod-шаблон для вашей сборки, основанный на <registry>/microsoft/dotnet:2.1-sdk.Скомпилируйте ваше приложение в этом модуле обычным способом dotnet.
  • Сохраните вторую часть вашего Dockerfile, но просто скопируйте скомпилированный артефакт в изображение docker.

В итоге выпереместите первую часть вашего Dockerfile в Jenkinsfile, чтобы выполнить сборку приложения.Вторая часть остается сделать сборкой docker из уже скомпилированного двоичного файла.

Файл Jenkins будет выглядеть примерно так:

podTemplate(
    ...,
    containers: ['microsoft/dotnet:2.1-sdk', 'docker:1.13.1'],
    ...
) {
    container('microsoft/dotnet:2.1-sdk') {
        stage("Compile Code") {
            sh "dotnet restore"
            sh "dotnet publish -c Release -o out"
        }
    }
    container('docker:1.13.1') {
        stage("Build Docker image") {
            docker.build("mydockerimage:1.0")
        }
    }
}

Этот файл Jenkins далек от завершения и только иллюстрирует, как ондолжно сработать.Дополнительную документацию можно найти здесь:

Плагин Jenkins kubernetes

Глобальная переменная док-станции Jenkins в скриптовом конвейере

0 голосов
/ 12 декабря 2018

Это мое окончательное рабочее решение.

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
ADD output/out /output
WORKDIR /output
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 sometag:v${BUILD_NUMBER} -f Dockerfile-build ."
                    echo 'Build Completed'
                }               
            }
        }
        stage('Extract artifact') {
            steps {
                script {
                    echo 'Extract...'
                    sh "docker run -d --name build-stage-container sometag:v${BUILD_NUMBER}"
                    sh 'mkdir output'
                    sh 'docker cp build-stage-container:/app/aspnetapp/MyProject.WebApi/out output'
                    sh 'docker rm -f build-stage-container'
                    sh "docker rmi -f sometag:v${BUILD_NUMBER}"
                    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'
                            sh "docker rmi -f ${docker_repository_url}/${artifact_group}/${artifact_name}:v${BUILD_NUMBER}"
                    }

                }               
            }
        }
    }
}
0 голосов
/ 10 декабря 2018

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.

Для этого у вас может быть один Dockerfile, чтобы построить свой артефакт и запустить одноразовый контейнер на основе этого изображения, из которого можно извлечь артефакт.Вам не нужно запускать контейнер, вы можете просто создать его с помощью docker create (это создаст слой контейнера для записи):

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

Затем вы можете иметь второй Dockerfileсоздать изображение, копирующее артефакт, извлеченный из предыдущего этапа, с простым COPY из контекста сборки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...