簡體   English   中英

使用 Jenkins 聲明式管道為 dockerfile 代理設置構建參數

[英]Setting build args for dockerfile agent using a Jenkins declarative pipeline

我正在使用聲明性管道語法在 docker 容器內執行一些 CI 工作。

我注意到 Jenkins 的 Docker 插件使用主機中 jenkins 用戶的用戶 ID 和組 ID 運行一個容器(即,如果 jenkins 用戶的用戶 ID 為 100 和組 ID 111,它將運行管道創建一個容器命令docker run -u 100:111 ... )。

我遇到了一些問題,因為容器將與非現有用戶一起運行(特別是我遇到了用戶沒有主目錄的一些問題)。 所以我想創建一個 Dockerfile,它將接收用戶 id 和組 id 作為構建參數,並在容器內創建一個合適的 jenkins 用戶。 Dockerfile 看起來像這樣:

FROM ubuntu:trusty
ARG user_id
ARG group_id

# Add jenkins user
RUN groupadd -g ${group_id} jenkins
RUN useradd jenkins -u ${user_id} -g jenkins --shell /bin/bash --create-home
USER jenkins

...

dockerfile 代理有一個additionalBuildArgs屬性,所以我可以讀取主機中 jenkins 用戶的用戶 ID 和組 ID 並將它們作為構建參數發送,但我現在遇到的問題是似乎沒有辦法執行這些在指定代理之前聲明性管道中的命令。 我希望我的 Jenkinsfile 是這樣的:

// THIS WON'T WORK
def user_id = sh(returnStdout: true, script: 'id -u').trim()
def group_id = sh(returnStdout: true, script: 'id -g').trim()

pipeline {
  agent {
    dockerfile {
      additionalBuildArgs "--build-arg user_id=${user_id} --build-arg group_id=${group_id}"
    }
  }
  stages {
    stage('Foo') {
      steps {
        ...
      }
    }
    stage('Bar') {
      steps {
        ...
      }
    }
    stage('Baz') {
      steps {
        ..
      }
    }
    ...
  }
}

我有什么辦法可以做到這一點嗎? 我還嘗試將管道指令包裝在節點內,但管道需要位於文件的根目錄。

我驗證了在沒有節點的情況下嘗試分配 user_id 和 group_id 不起作用,正如您發現的那樣,但這對我分配這些值並稍后訪問它們有用:

def user_id
def group_id
node {
  user_id = sh(returnStdout: true, script: 'id -u').trim()
  group_id = sh(returnStdout: true, script: 'id -g').trim()
}

pipeline {
  agent { label 'docker' }
  stages {
    stage('commit_stage') {
      steps {
        echo 'user_id'
        echo user_id
        echo 'group_id'
        echo group_id
      }
    }
  }
}

希望這些也適用於您的additionalBuildArgs語句。

在評論中,您指出在使用聲明性管道之外的 user_id 和 group_id 來配置 dockerfile 之前,您指出最有可能存在嚴重缺陷的方法是:它發現 user_id 的從站不一定與它用於啟動基於 docker 的構建的從站。 我沒有任何辦法解決這個問題,同時還要保持聲明性的 Jenkinsfile 約束。

您可以通過使用全局代理聲明來保證所有階段都有一個從站: Jenkins 聲明性管道:當代理僅為管道設置時,哪個工作區與階段相關聯?

但是具有相同標簽的多個節點引用並不能保證相同的工作空間: Jenkins 聲明性管道:當代理僅為管道設置時,什么工作空間與階段相關聯?

您還可以添加這樣的塊:

agent {
    dockerfile {

        args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
    }
}

這將允許容器具有正確的用戶和組 ID。

您還可以使用 args 參數來解決該問題。
管道語法中所述

docker 還可以選擇接受一個args參數,該參數可能包含直接傳遞給 docker run 調用的參數。

當在代理部分使用 dockerfile 而不是 docker 時,這也是可能的。

我有和你一樣的問題,以下幾行對我來說很好:

       agent { 
            dockerfile { 
                dir 'Docker/kubernetes-cli' 
                args '-u 0:0' //Forces Container tu run as User Root                    
                reuseNode true
            }
        }

我相信我們找到了解決這個問題的好方法。

我們有一個作為 docker 實例運行的 Jenkins 部署,我已經為 /var/jenkins_home 映射了一個卷並將 .ssh 文件夾添加到 /var/jenkins_home/.ssh

我們還使用 dockerfile 代理指令在 docker 容器內運行所有構建。 有時我們需要通過 ssh 通過 git 訪問我們的一些私有作曲家庫。

我們通過安裝項目 deps(composer)來利用 docker 圖像緩存,這意味着我們只有在 deps 發生變化時才重建構建容器。 這意味着我們需要在 docker build 期間注入一個 SSH 密鑰。

請參閱這些示例文件:

項目/詹金斯文件

def SSH_KEY

node {
  SSH_KEY = sh(returnStdout: true, script: 'cat /var/jenkins_home/.ssh/id_rsa')
}

pipeline {
  agent {
    dockerfile {
      filename 'Dockerfile'
      additionalBuildArgs '--build-arg SSH_KEY="' + SSH_KEY + '"'
      reuseNode true
    }
  }
  stages {
    stage('Fetch Deps') {
      steps {
        sh 'mv /home/user/app/vendor vendor'
      }
    }
    stage('Run Unit Tests') {
      steps {
        sh './vendor/bin/phpunit'
      }
    }
  }
}

項目/Dockerfile

FROM mycompany/php7.2-common:1.0.2

# Provides the image for building mycompany/project on Jenkins.

WORKDIR /home/user/app

ARG SSH_KEY # should receive a raw SSH private key during build.
ADD composer.json .
RUN add-ssh-key "${SSH_KEY}" ~/.ssh/id_rsa && \
    composer install && \
    remove-ssh-keys

# Note: add-ssh-key and remove-ssh-keys are our shell scripts put in
# the base image to reduce boilerplate for common tasks.

我嘗試在 additionalBuildArgs 中使用單引號並將 id 命令直接放在 build-args 上並且它起作用了

pipeline {
  agent {
    dockerfile {
      additionalBuildArgs '--build-arg user_id=$(id -u) --build-arg group_id=$(id -g)'
    }
  }
...

如果您對 Jenkins 具有管理員訪問權限,則可以添加以下兩個腳本批准:

staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods execute java.lang.String
staticMethod org.codehaus.groovy.runtime.ProcessGroovyMethods getText java.lang.Process

在這個 URI 中: http://${jenkins_host:port}/jenkins/scriptApproval/

這將允許您以這種方式在 master 中執行 shell 命令:

def user = 'id -u'.execute().text
node {
   echo "Hello World ${user}"
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM