はじめに
今回はちょっと大規模に見えるかもしれません。私はまず、ECRからOpenShiftイメージレジストリにコンテナイメージをコピーするJenkinsパイプライン「ecr-image-copyer.jenkinsfile」を作成しました。 今回はこの、Jenkinsパイプライン「ecr-image-copyer.jenkinsfile」を呼び出して複数回実行する、別のパイプラインを作成します。
呼び出される側のJenkinsパイプライン「ecr-image-copyer.jenkinsfile」は存在するが、呼び出す側のJenkinsパイプラインは、何もない状態です。 そのような、何もない状態の物を生成AIで作成してみることにします。
JenkinsパイプラインでECRからOpenShiftへのコンテナイメージ一括コピー
プロンプト
wrapperを作る
私は、ECRからOpenShiftイメージレジストリにコンテナイメージをコピーするJenkinsパイプライン「ecr-image-copyer.jenkinsfile」を作成しました。
このJenkinsパイプライン「ecr-image-copyer.jenkinsfile」は、1つの「ECR_REPOSITORY」内のコンテナイメージを、「OPENSHIFT_PROJECT」にコピーします。
これから、Jenkinsパイプライン「ecr-image-copyer.jenkinsfile」を複数回実行し、複数の「ECR_REPOSITORY」内のコンテナイメージを、1つの「OPENSHIFT_PROJECT」にコピーするための、新たなJenkinsパイプライン「multi-ecr-image-copyer.jenkinsfile」を作成します。
Jenkinsパイプライン「multi-ecr-image-copyer.jenkinsfile」を作成してください。
「multi-ecr-image-copyer.jenkinsfile」が受け取るJenkinsパイプラインパラメーター
パラメーター1:「ECR_REPOSITORY」
値はtext(以下のような改行付きテキスト)
example-repo1 example-repo2
パラメーター2:「OPENSHIFT_PROJECT」
値はstring
example-project
「multi-ecr-image-copyer.jenkinsfile」がecr-image-copyerに与えるパラメーター
以下のパラメーター値を、wrapperに与えられた値でオーバーライドする。
ECR_REPOSITORY OPENSHIFT_PROJECT
以下のパラメーターのdefaultValueを使う。
string(name: 'AWS_ACCOUNT_ID', defaultValue: '123456789012', description: 'AWS Account ID') string(name: 'AWS_REGION', defaultValue: 'us-west-2', description: 'AWS region') string(name: 'AWS_ACCESS_KEY_ID', defaultValue: 'ABCD1234EFGH5678IJKL', description: 'AWS Access Key ID') string(name: 'AWS_SECRET_ACCESS_KEY', defaultValue: 'abcd1234efgh5678ijklmnopqrstuvwx', description: 'AWS Secret Access Key') string(name: 'OPENSHIFT_REGISTRY', defaultValue: 'image-registry.openshift.example.com:5000', description: 'OpenShift registry') string(name: 'OPENSHIFT_REGISTRY_CREDENTIALSID', defaultValue: 'example-credentials', description: 'OpenShift registry credentials ID') string(name: 'HTTP_PROXY', defaultValue: 'http://proxy.example.com:8080', description: 'HTTP proxy') string(name: 'HTTPS_PROXY', defaultValue: 'http://proxy.example.com:8080', description: 'HTTPS proxy') string(name: 'NO_PROXY', defaultValue: 'example-registry.openshift.svc', description: 'No proxy')
ecr-image-copyer.jenkinsfile
pipeline { agent { kubernetes { cloud 'openshift' yaml ''' apiVersion: v1 kind: Pod spec: serviceAccountName: jenkins affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-role.kubernetes.io/infra operator: Exists containers: - name: jnlp image: image-registry.openshift.example.com:5000/example-cicd/custom-jenkins-agent args: ['\$(JENKINS_SECRET)', '\$(JENKINS_NAME)'] tty: false resources: requests: cpu: 500m memory: 1024Mi limits: cpu: 500m memory: 1024Mi ''' } } environment { AWS_ACCOUNT_ID = "${params.AWS_ACCOUNT_ID}" AWS_REGION = "${params.AWS_REGION}" ECR_REPOSITORY = "${params.ECR_REPOSITORY}" AWS_ACCESS_KEY_ID = "${params.AWS_ACCESS_KEY_ID}" AWS_SECRET_ACCESS_KEY = "${params.AWS_SECRET_ACCESS_KEY}" OPENSHIFT_REGISTRY = "${params.OPENSHIFT_REGISTRY}" OPENSHIFT_PROJECT = "${params.OPENSHIFT_PROJECT}" OPENSHIFT_REGISTRY_CREDENTIALSID = "${params.OPENSHIFT_REGISTRY_CREDENTIALSID}" HTTP_PROXY = "${params.HTTP_PROXY}" HTTPS_PROXY = "${params.HTTPS_PROXY}" NO_PROXY = "${params.NO_PROXY}" } parameters { string(name: 'AWS_ACCOUNT_ID', defaultValue: '123456789012', description: 'AWS Account ID') string(name: 'AWS_REGION', defaultValue: 'us-west-2', description: 'AWS region') string(name: 'ECR_REPOSITORY', defaultValue: 'example-ecr-repo', description: 'ECR repository name') string(name: 'AWS_ACCESS_KEY_ID', defaultValue: 'ABCD1234EFGH5678IJKL', description: 'AWS Access Key ID') string(name: 'AWS_SECRET_ACCESS_KEY', defaultValue: 'abcd1234efgh5678ijklmnopqrstuvwx', description: 'AWS Secret Access Key') string(name: 'OPENSHIFT_REGISTRY', defaultValue: 'image-registry.openshift.example.com:5000', description: 'OpenShift registry') string(name: 'OPENSHIFT_PROJECT', defaultValue: 'example-project', description: 'OpenShift project') string(name: 'OPENSHIFT_REGISTRY_CREDENTIALSID', defaultValue: 'example-credentials', description: 'OpenShift registry credentials ID') string(name: 'HTTP_PROXY', defaultValue: 'http://proxy.example.com:8080', description: 'HTTP proxy') string(name: 'HTTPS_PROXY', defaultValue: 'http://proxy.example.com:8080', description: 'HTTPS proxy') string(name: 'NO_PROXY', defaultValue: 'example-registry.openshift.svc', description: 'No proxy') } stages { stage('Get ECR Images') { steps { script { def ecrImages = sh(script: ''' aws ecr describe-images --repository-name ${ECR_REPOSITORY} --region ${AWS_REGION} \ --query 'imageDetails[?imageScanStatus.status==`COMPLETE` && imageTags!=null]' \ --output json ''', returnStdout: true).trim() env.ECR_IMAGES = ecrImages } } } stage('Check for Critical Findings') { steps { script { def criticalImages = sh(script: """ echo '${ECR_IMAGES}' | jq '[.[] | select(.imageScanFindingsSummary.findingSeverityCounts.CRITICAL > 0)]' """, returnStdout: true).trim() writeFile file: 'critical_images.json', text: criticalImages def criticalImagesJSON = readJSON file: 'critical_images.json' if (criticalImagesJSON != '[]') { criticalImagesJSON.each { image -> def tag = image.imageTags[0] def SeverityCountsCRITICAL = image.imageScanFindingsSummary.findingSeverityCounts.CRITICAL def messageDetails = "${ECR_REPOSITORY}:${tag} CRITICAL: ${SeverityCountsCRITICAL}" echo "Warning: There are images with critical findings. ${messageDetails}" } } } } } stage('Filter Safe Images') { steps { script { def safeImages = sh(script: """ echo '${ECR_IMAGES}' | jq '[.[] | select(.imageScanFindingsSummary.findingSeverityCounts.CRITICAL == null)]' """, returnStdout: true).trim() // env.SAFE_IMAGES = safeImages writeFile file: 'safe_images.json', text: safeImages } } } stage('Copy Images to OpenShift') { steps { script { def images = readJSON file: 'safe_images.json' images.each { image -> def tag = image.imageTags[0] def ecrRepository = "${ECR_REPOSITORY}" def imageName = ecrRepository.replaceAll('/', '-') def sourceImage = "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${ECR_REPOSITORY}:${tag}" def targetImage = "${OPENSHIFT_REGISTRY}/${OPENSHIFT_PROJECT}/${imageName}:${tag}" withCredentials([file(credentialsId: "${OPENSHIFT_REGISTRY_CREDENTIALSID}", variable: 'DEST_AUTHFILE')]) { sh(script: """ skopeo copy --debug \ --src-creds=AWS:\$(aws ecr get-login-password --region="${AWS_REGION}") \ --dest-authfile=${DEST_AUTHFILE} \ --dest-tls-verify=false \ docker://${sourceImage} \ docker://${targetImage} """) } } } } } } post { always { cleanWs() } } }
回答
以下は、指定された要件に基づいて作成したJenkinsパイプライン「multi-ecr-image-copyer.jenkinsfile」です。このパイプラインは、「ecr-image-copyer.jenkinsfile」を呼び出して、複数の「ECR_REPOSITORY」からイメージをコピーします。
pipeline { agent any parameters { text(name: 'ECR_REPOSITORY', defaultValue: '''example-repo1 example-repo2''', description: 'ECR repositories (one per line)') string(name: 'OPENSHIFT_PROJECT', defaultValue: 'example-project', description: 'OpenShift project') } stages { stage('Trigger ECR Image Copy Jobs') { steps { script { def repositories = params.ECR_REPOSITORY.split('\n') def openshiftProject = params.OPENSHIFT_PROJECT repositories.each { repo -> build job: 'ecr-image-copyer', parameters: [ string(name: 'ECR_REPOSITORY', value: repo), string(name: 'OPENSHIFT_PROJECT', value: openshiftProject), string(name: 'AWS_ACCOUNT_ID', value: '123456789012'), string(name: 'AWS_REGION', value: 'us-west-2'), string(name: 'AWS_ACCESS_KEY_ID', value: 'ABCD1234EFGH5678IJKL'), string(name: 'AWS_SECRET_ACCESS_KEY', value: 'abcd1234efgh5678ijklmnopqrstuvwx'), string(name: 'OPENSHIFT_REGISTRY', value: 'image-registry.openshift.example.com:5000'), string(name: 'OPENSHIFT_REGISTRY_CREDENTIALSID', value: 'example-credentials'), string(name: 'HTTP_PROXY', value: 'http://proxy.example.com:8080'), string(name: 'HTTPS_PROXY', value: 'http://proxy.example.com:8080'), string(name: 'NO_PROXY', value: 'example-registry.openshift.svc') ] } } } } } post { always { cleanWs() } } }
説明
やってみた感想
- 生成された呼び出し側のJenkinsパイプライン「multi-ecr-image-copyer.jenkinsfile」は、そのまま動作しました。
- 生成されたパイプラインの「説明」まであり、懇切丁寧ですね。
- 「別のパイプラインを呼び出す方法」を自分で調べることなく、完成品を手に入れることができました。
- 「一部のパラメーターを実行時に指定できるようにして、それ以外のパラメーターには初期値を与える。」という指示もきちんと反映されました。
- 呼び出される側のプログラムコードをまず作り、呼び出す側を生成AIで作るというアプローチは、有効のようです。
- とりあえず「単数の物を処理するプログラム」を作成すれば、「それを複数回実行する側のプログラム」を生成AIで作成できるわけです。
- 私も最近は、ずいぶんと長いプロンプトを書くようになってきました。