宣言型パイプライン構文を使用して、Dockerコンテナー内でCIの作業を行っています。
JenkinsのDockerプラグインは、ホストのjenkinsユーザーのユーザーIDとグループIDを使用してコンテナーを実行します(つまり、jenkinsユーザーがユーザーID 100とグループID 111を持っている場合、パイプラインを実行してコンテナーを作成しますコマンド docker run -u 100:111 ...
)。
コンテナが存在しないユーザーで実行されるため、これにはいくつかの問題がありました(特に、ユーザーがホームディレクトリを持っていないという問題に遭遇しました)。そこで、ユーザーIDとグループIDをビルド引数として受け取り、コンテナー内で適切なjenkinsユーザーを作成するDockerfileを作成することを考えました。 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
ステートメントでも機能することを願っています。
コメントで、dockerfileを構成するために使用する前に宣言的なパイプラインの外側でuser_idとgroup_idを把握するアプローチの最も可能性が高い重大な欠陥を指摘しました:user_idを検出するスレーブは必ずしも一致しませんDockerベースのビルドを開始するために使用するスレーブ。宣言的なJenkinsfile制約を維持しながら、これを回避する方法はありません。
グローバルエージェント宣言を使用すると、すべてのステージで1つのスレーブを保証できます。 Jenkins宣言パイプライン:パイプラインのみにエージェントが設定されている場合、ステージに関連付けられるワークスペースは何ですか?
ただし、同じラベルを持つ複数のノード参照は同じワークスペースを保証しません: Jenkins宣言的パイプライン:パイプラインのみにエージェントが設定されている場合、ステージに関連付けられるワークスペースは何ですか?
次のようなブロックを追加することもできます。
agent {
dockerfile {
args '-v /etc/passwd:/etc/passwd -v /etc/group:/etc/group'
}
}
これにより、コンテナは正しいユーザーIDとグループIDを持つことができます。
Argsパラメーターを使用して問題を解決することもできます。
「 パイプライン構文 :」で説明されているとおり
dockerは、オプションでargsパラメーターも受け入れます。このパラメーターには、Docker実行呼び出しに直接渡す引数を含めることができます。
これは、エージェントセクションでdockerの代わりにdockerfileを使用する場合にも可能です。
私はあなたと同じ問題を抱えており、次の行がうまく機能しています:
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コンテナ内で実行します。時々git over sshを介してプライベートのcomposerライブラリにアクセスする必要があります。
プロジェクトdeps(composer)をインストールすることにより、Dockerイメージキャッシングを活用します。つまり、depsが変更された場合にのみビルドコンテナーを再構築します。これは、Dockerのビルド中にSSHキーを挿入する必要があることを意味します。
これらのサンプルファイルを参照してください:
project/Jenkinsfile
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.
jenkinsへの管理者アクセス権がある場合、次の2つのスクリプト承認を追加できます。
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/
これにより、次の方法でマスターでシェルコマンドを実行できます。
def user = 'id -u'.execute().text
node {
echo "Hello World ${user}"
}