すべてのプロダクト
Search
ドキュメントセンター

Container Registry:Jenkinsを使用して画像のCI/CDパイプラインを作成する

最終更新日:Jun 27, 2024

ソースコードの構築、イメージのプッシュからアプリケーションの展開までの自動操作を実装する場合は、Jenkinsを使用して、イメージの継続的統合または継続的配信 (CI/CD) パイプラインを作成できます。 ソースコードをGitLabにコミットすると、Container Registryは自動的にソースコードを使用してイメージをビルドします。 次に、Container Service for Kubernetes (ACK) がイメージをプルしてアプリケーションをデプロイし、Container Registryがイベント通知をDingTalkグループに送信します。

前提条件

  • Git、GitLab、Jenkinsがインストールされています。

    説明

    GitLabにはJDK11の代わりにJDK8がインストールされています。 一部のGitLabプラグインはJDK11で実行できません。

  • ACR Enterprise Editionインスタンスが作成され、インスタンスのインターネットアクセスが有効になっています。 詳細については、「Container Registry Enterprise Editionインスタンスの作成」および「インターネット経由のアクセスの設定」をご参照ください。

  • Container Registry Enterprise EditionのAdvanced Editionインスタンスと同じリージョンに存在するACKクラスターが作成されます。 詳細については、「ACK管理クラスターの作成」をご参照ください。

  • DingTalkチャットボットが作成されます。 DingTalkチャットボットのwebhook URLとシークレットトークンが記録されます。 詳細については、「手順1: DingTalkチャットボットの作成」をご参照ください。

  • Container Registryのパイプライン機能を使用するには、インスタンスをAdvanced Editionにアップグレードする必要があります。 詳細については、「」をご参照ください。

Jenkinsを使用して画像のCIパイプラインを作成する

ソースコードをGitLabにコミットすると、Container Registryは自動的にソースコードを使用してイメージをビルドします。 イメージをスキャンすると、Container Registryは自動的にイベント通知をDingTalkグループに送信します。

  1. GitLabでプロジェクトを作成します。

    1. GitLabにログインします。

    2. GitLabコンソールの上部のナビゲーションバーで、プロジェクト > プロジェクト.

    3. On theプロジェクトページをクリックします。新しいプロジェクト右上隅をクリックし、空白プロジェクトの作成.

    4. On the空白プロジェクトの作成ページを設定し、プロジェクト名,プロジェクトURLプロジェクトスラッグパラメータ, set可視性レベルプライベートをクリックし、プロジェクトの作成.

      创建Project

    5. 作成Dockerfile,pom.xml,DemoApplication.java、およびHelloController.javaオンプレミスコンピュータ上のファイル。

      • Dockerfile

        FROM registry.cn-hangzhou.aliyuncs.com/public-toolbox/maven:3.8.3-openjdk-8-aliyun AS build
        COPY src /home/app/src
        COPY pom.xml /home/app
        RUN ["/usr/local/bin/mvn-entrypoint.sh","mvn","-f","/home/app/pom.xml","clean","package","-Dmaven.test.skip=true"]
        
        FROM registry.cn-hangzhou.aliyuncs.com/public-toolbox/openjdk:8-jdk-alpine
        COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo-0.0.1-SNAPSHOT.jar
        EXPOSE 8080
        ENTRYPOINT ["java","-jar","/usr/local/lib/demo-0.0.1-SNAPSHOT.jar"]
      • pom.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
            <modelVersion>4.0.0</modelVersion>
            <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.6.1</version>
                <relativePath/> <!-- lookup parent from repository -->
            </parent>
            <groupId>com.example</groupId>
            <artifactId>demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <name>demo</name>
            <description>Demo project for Spring Boot</description>
            <properties>
                <java.version>1.8</java.version>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-freemarker</artifactId>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
        
                <dependency>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                    <optional>true</optional>
                </dependency>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-test</artifactId>
                    <scope>test</scope>
                </dependency>
                <dependency>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-core</artifactId>
                    <version>2.13.2</version>
                </dependency>
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <excludes>
                                <exclude>
                                    <groupId>org.projectlombok</groupId>
                                    <artifactId>lombok</artifactId>
                                </exclude>
                            </excludes>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        
        </project>
      • DemoApplication.java

        package com.example.demo;
        
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        
        import java.util.TimeZone;
        
        @SpringBootApplication
        public class DemoApplication {
        
            public static void main(String[] args) {
                TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
                SpringApplication.run(DemoApplication.class, args);
            }
        
        }
      • HelloController.java

        package com.example.demo;
        
        import lombok.extern.slf4j.Slf4j;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RestController;
        
        import javax.servlet.http.HttpServletRequest;
        import java.text.SimpleDateFormat;
        import java.util.Date;
        
        @RestController
        @Slf4j
        public class HelloController {
        
            @RequestMapping({"/hello", "/"})
            public String hello(HttpServletRequest request) {
                return "Hello World at " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
            }
        }
    6. 次のコマンドを実行して、ビルドファイルをGitLabにアップロードします。

      cd java-web  # Go to the directory where the building file resides. 
      git remote set-url origin http://8.218.20*.***/shoppingmall/java-web.git
      git push origin master
      * [new branch]      master -> master
  2. Jenkinsでイメージをビルドするパイプラインを作成します。

    1. JenkinsでGitLabのSecure Shell (SSH) キーペアを設定します。

      1. Jenkins にログインします。

      2. Jenkinsダッシュボードの左側のナビゲーションウィンドウで、[Jenkinsの管理] をクリックします。

      3. [セキュリティ] セクションで、[資格情報の管理] をクリックします。

      4. [Jenkinsにスコープされたストア] セクションで、[ストア] 列の [Jenkins] をクリックし、[グローバル認証情報] をクリックします。

      5. 左側のナビゲーションウィンドウで、[資格情報の追加] をクリックします。

      6. Kindパラメーターを [SSH Username with private key] に設定し、[Description] パラメーターと [Username] パラメーターの値を入力し、[enter directly] を選択し、[OK] をクリックします。

        [グローバル資格情報] ページで、資格情報のIDが自動的に生成されます。 IDを記録します。

    2. パイプラインを作成します。

      1. Jenkinsダッシュボードの左側のナビゲーションウィンドウで、[新しい項目] をクリックします。

      2. パイプラインの名前を入力し、[パイプライン] を選択し、[OK] をクリックします。

      3. [ビルドトリガー] タブをクリックし、[変更がGitLabにプッシュされたときにビルド] を選択し、[イベントのプッシュ] を選択します。

        変更がGitLabにプッシュされたときにビルドの右側にwebhook URLを記録します。

      4. [詳細設定] をクリックし、[シークレットトークン] の右下隅にある [生成] をクリックします。

        Jenkinsによって生成された秘密トークンを記録します。

      5. [パイプライン] タブをクリックし、次のテンプレートのパラメーターの値を実際の値に置き換えます。 変更したコンテンツをコードエディターにコピーし、[保存] をクリックします。

        def git_auth_id = "6d5a2c06-f0a7-43c8-9b79-37b8c266****" # The ID of the credential.
        def git_branch_name = "master" # The name of the branch.
        def git_url = "git@172.16.1*.***:shoppingmall/java-web.git" # The address of the GitLab repository.
        def acr_url = "s*****-devsecops-registry.cn-hongkong.cr.aliyuncs.com" # The endpoint of the image repository.
        def acr_username = "acr_test_*****@test.aliyunid.com" # The username of the container image.
        def acr_password = "HelloWorld2021" # The password of the container image.
        def acr_namespace = "ns" # The name of the namespace.
        def acr_repo_name = "test" # The name of the image repository.
        def tag_version = "0.0.1" # The tag of the container image.
        node {
        
            stage('checkout git repo') {
                checkout([$class: 'GitSCM', branches: [[name: "*/${git_branch_name}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth_id}", url: "${git_url}"]]])
            }
            stage('build image') {
                sh "sudo docker build -t java-web:${tag_version} ."
                sh "sudo docker tag java-web:${tag_version} ${acr_url}/${acr_namespace}/${acr_repo_name}:${tag_version}"
            }
            stage('push image') {
                sh "sudo docker login --username=${acr_username} --password=${acr_password} ${acr_url}"
                sh "sudo docker push ${acr_url}/${acr_namespace}/${acr_repo_name}:${tag_version}"
            }
        }
  3. webhook URLをGitLabに追加します。

    1. GitLabにログインします。

    2. [プロジェクト] ページで、作成したプロジェクトの名前をクリックします。

    3. 左側のナビゲーションウィンドウで、[設定] > [Webhooks] を選択します。 webhook URLとシークレットトークンを入力し、[SSL検証の有効化] をクリアし、[webhooksの追加] をクリックします。

  4. イベント通知ルールを作成します。

    1. Container Registryコンソールにログインします。

    2. 上部のナビゲーションバーで、リージョンを選択します。

    3. 左側のナビゲーションウィンドウで、[インスタンス] をクリックします。

    4. [インスタンス] ページで、管理するEnterprise Editionインスタンスをクリックします。

    5. インスタンスの詳細ページの左側のナビゲーションウィンドウで、インスタンス > イベント通知.

    6. On theイベントルールタブをクリックします。ルールの作成.

    7. では、イベントスコープルール作成ウィザードのステップで、ルール名パラメーターを設定し、イベントタイプパラメーターを画像がスキャンされます、選択スキャン完了、セット有効範囲名前空間名前空間の名前としてnsを選択し、次へ.

    8. では、イベント通知ステップ、セット通知方法DingTalkDingTalkチャットボットのwebhook URLとシークレットトークンを入力し、保存.

  5. イメージの構築をトリガーします。

    次のコマンドを実行し、HelloController.javaファイルのパラメーターの値を実際の値に置き換えます。 GitLabにファイルをコミットして、イメージビルドをトリガーします。

    vim java/com/example/demo/HelloController.java # Replace the value of the parameter in the HelloController.java file with your actual value.
    git add . && git commit -m 'commit' && git push origin # Commit the file to GitLab.

    しばらく待って Container Registry Enterprise Editionインスタンスの詳細ページの左側のナビゲーションウィンドウで、[リポジトリ] > [リポジトリ] を選択します。 表示されるページの右側で、テストリポジトリをクリックします。 リポジトリの管理ページの左側のナビゲーションウィンドウで、[タグ] をクリックします。 [タグ] ページに画像が生成されます。

  6. セキュリティスキャンを設定します。

    1. [タグ] ページで、セキュリティスキャンイメージの [アクション] 列に表示されます。

    2. [セキュリティスキャン] ページで、[今すぐスキャン] をクリックします。

      イメージがスキャンされると、Container RegistryはDingTalkグループに通知を送信します。

Jenkinsを使用して画像のCDパイプラインを作成する

GitLabでソースコードをコミットすると、Container Registryは自動的にソースコードを使用してイメージをビルドします。 イメージが構築されると、配信チェーンが自動的にトリガーされます。 配信チェーンが実行されると、HTTPリクエストが自動的にJenkinsに送信されます。 次に、アプリケーションをデプロイするためにイメージを再度プルするために、ACKでのデプロイがトリガーされます。

  1. アプリケーションを作成します。

    1. ACKコンソールにログインします。

    2. ACKコンソールの左側のナビゲーションウィンドウで、[クラスター] をクリックします。

    3. [クラスター] ページで、管理するクラスターを見つけ、クラスターの名前をクリックするか、[操作] 列の [詳細] をクリックします。 クラスターの詳細ページが表示されます。

    4. 詳細ページの左側のナビゲーションウィンドウで、[ワークロード] > [デプロイ] を選択します。

    5. On theデプロイメントページをクリックします。YAMLから作成する右上隅にあります。

    6. On the作成ページの値を選択します。名前空間、選択カスタムからサンプルテンプレートドロップダウンリストで、次のコンテンツをテンプレートにコピーし、作成.

      説明

      ACKおよびContainer Registryでシークレットなしでイメージをプルする機能を有効にしない場合は、Container Registryのインターネット機能を介したアクセスを有効にし、イメージタイプをpublicに設定する必要があります。 詳細については、「インターネット経由のアクセスの設定」をご参照ください。

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        creationTimestamp: null
        labels:
          app: demo
        name: demo
      spec:
        replicas: 3
        minReadySeconds: 5
        progressDeadlineSeconds: 60
        revisionHistoryLimit: 5
        selector:
          matchLabels:
            app: demo
        strategy:
          rollingUpdate:
            maxUnavailable: 1
          type: RollingUpdate
        template:
          metadata:
            annotations:
              prometheus.io/port: "9797"
              prometheus.io/scrape: "true"
            creationTimestamp: null
            labels:
              app: demo
          spec:
            containers:
            - image: s*****-devsecops-registry.cn-hongkong.cr.aliyuncs.com/ns/test:0.0.1 
              imagePullPolicy: Always
              name: demo
              ports:
              - containerPort: 8080
                name: http
                protocol: TCP
              readinessProbe:
                initialDelaySeconds: 5
                tcpSocket:
                  port: 8080
                timeoutSeconds: 5
              resources:
                limits:
                  cpu: "2"
                  memory: 512Mi
                requests:
                  cpu: 100m
                  memory: 64Mi
      status: {}
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: demo-svc
      spec:
        selector:
          app: demo
        ports:
          - protocol: TCP
            port: 80
            targetPort: 8080
      ---
      apiVersion: extensions/v1beta1
      kind: Ingress
      metadata:
        name: demo
        labels:
          app: demo
      spec:
        rules:
          - host: app.demo.example.com
            http:
              paths:
                - backend:
                    serviceName: demo-svc
                    servicePort: 80
      ---
                                      
    7. [デプロイメント] ページで、アプリケーションデモの名前をクリックします。 [アクセス方法] タブをクリックします。

      [アクセス方法] タブで外部エンドポイントを取得します。

    8. ローカルホストの次の内容を入力します。

      <The external endpoint> app.demo.example.com
    9. 入力app.demo.example.comブラウザのアドレスバーにあります。

      应用前の図のようにページが表示されると、アプリケーションがデプロイされます。

  2. アプリケーショントリガーを作成します。

    1. [デプロイメント] ページで、アプリケーションデモの名前をクリックします。

    2. アプリケーションの詳細ページで、[トリガー] タブをクリックします。 次に、[トリガーの作成] をクリックします。

    3. では、トリガーの作成ダイアログボックス, setアクション再デプロイをクリックし、OK.

      [トリガー] タブでwebhook URLを取得します。

  3. パイプラインを作成します。

    1. Jenkinsにログインします。

    2. 左側のナビゲーションウィンドウで、新しいアイテム.

    3. パイプラインの名前を入力し、パイプライン.

    4. をクリックし、ビルドトリガータブと選択一般的なWebhookトリガー.

      Generic Webhook Triggerセクションでは、HTTPリクエストのwebhook URL (JENKINS_URL/generic-webhook-trigger/invoke) を取得できます。 この例では、汎用webhookトークンはhelloworld2021に設定されています。 したがって、webhook URLはJENKINS_URL/generic-webhook-trigger/invoke?token=helloworld2021です。

    5. [パイプライン] タブをクリックし、次のテンプレートの汎用webhookトークンとwebhook URLを実際の値に置き換えます。 変更したコンテンツをコードエディターにコピーし、[保存] をクリックします。

      pipeline {
        agent any
        triggers {
          GenericTrigger(
           genericVariables: [
            [key: 'InstanceId', value: '$.data.InstanceId'],   
            [key: 'RepoNamespaceName', value: '$.data.RepoNamespaceName'],
            [key: 'RepoName', value: '$.data.RepoName'],
            [key: 'Tag', value: '$.data.Tag']
           ],
           causeString: 'Triggered on $ref',
           token: 'helloworld2021', # The generic webhook token. Replace the token with your actual value. 
           tokenCredentialId: '',
           printContributedVariables: true,
           printPostContent: true,
           silentResponse: false,
           regexpFilterText: '$ref'
          )
        }
        stages {
          stage('Some step') {
            steps {
              sh "echo 'will print post content'"
              sh "echo $InstanceId"
              sh "echo $RepoNamespaceName"
              sh "echo $RepoName"
              sh "echo $Tag"
              sh "echo 'redeploy to ACK or you can deoloy to other platforms use before message'"
              sh "curl 'https://cs.console.aliyun.com/hook/trigger?token=g****' # Replace the webhook URL with your actual value. 
              sh "echo 'done'"
            }
          }
        }
      }
  4. パイプラインを作成します。 詳細については、「配信チェーンの作成」をご参照ください。

  5. イベント通知ルールを作成します。

    1. Container Registry Enterprise Editionインスタンスの管理ページの左側のナビゲーションウィンドウで、インスタンス > イベント通知.

    2. On theイベントルールタブをクリックします。ルールの作成.

    3. では、イベントスコープルール作成ウィザードのステップで、ルール名パラメータ, setイベントタイプ配送チェーンが処理されます、選択成功、セット有効範囲名前空間[名前空間] ドロップダウンリストから [ns] を選択し、次へ.

    4. では、イベント通知ステップ、セット通知方法パラメーターをHTTPで取得したwebhook URLを入力します。ステップ3をクリックし、保存.

  6. 次のコマンドを実行し、HelloController.javaファイルのパラメーターの値を実際の値に置き換えます。 GitLabにコードをコミットして、イメージビルドをトリガーします。

    vim java/com/example/demo/HelloController.java # Replace the value of the parameter in the HelloController.java file with your actual value. 
    git add . && git commit -m 'add update' && git push origin   # Commit the file to GitLab.

    イメージが構築されると、配信チェーンがトリガーされます。 配信チェーンが実行された後、Deployment in ACKがトリガーされ、イメージを再度プルしてアプリケーションをデプロイします。

  7. 次のコマンドを実行して、アプリケーションが再デプロイされたかどうかを確認します。

    curl app.demo.example.com

    コマンド出力が変更されると、アプリケーションは再デプロイされます。