Versuchen Sie, Java-Bibliotheken mit AWS CodeArtifact zu verwalten

Einführung

AWS CodeArtifact, GA, im Juni 2020, für große Projekte möchte ich, dass ein lokales Repository eine gemeinsame Bibliothek verwaltet, aber ich möchte nicht die Mühe machen, EC2 oder einen Container dafür einzurichten ... Es scheint sehr einfach zu bedienen zu sein.

Dieses Mal werde ich also AWS CodeArtifact berühren, um die Java-Bibliothek zu verwalten. Da es eine große Sache ist, werde ich versuchen, es mit Maven und Gradle auszuführen, und sogar CI / CD der mit CodeArtifact verknüpften Bibliothek ausprobieren. Sie können jederzeit Official User Guide begleiten. (Zum Zeitpunkt des Schreibens dieses Artikels ist er noch auf Japanisch. Es gibt kein Handbuch)

Beachten Sie außerdem, wie im Benutzerhandbuch angegeben, dass die CLI nur verwendet werden kann, wenn sie auf die neueste Version aktualisiert wurde.

Versuchen Sie zunächst, ein Repository zu erstellen

Suchen Sie in der Dienstauswahl nach `` `CodeArtifact```, gehen Sie zum oberen Bildschirm und klicken Sie auf die Schaltfläche" Repository erstellen ". Anschließend werden Sie wie unten gezeigt nach dem Namen des Repositorys gefragt. Geben Sie ihm daher einen Textnamen.

キャプチャ1.png

Erstellen Sie als Nächstes eine Domain. Ich werde diesmal kein Cross-Account erstellen. Wählen Sie daher vorerst "dieses AWS-Konto" aus und geben Sie ihm einen textuellen Domainnamen. Legen Sie aus Sicherheitsgründen einen Kundenstammschlüssel fest.

キャプチャ2.png

Machen Sie nichts auf dem Bestätigungsbildschirm und "erstellen Sie ein Repository"!

キャプチャ3.png

Damit ist die Erstellung abgeschlossen. Als nächstes verbinden wir uns. Für Verbindungseinstellungen klicken Sie im Detailbild des erstellten Repositorys auf "Verbindungsverfahren anzeigen".

キャプチャ4.png

Wenn Sie den Paketmanager-Client auswählen, wird Folgendes angezeigt. Aus irgendeinem Grund werden die Bindestriche von "id" verdoppelt. Ich weiß nicht, ob es so etwas oder ein Fehler ist. Ein Geheimnis.

キャプチャ5.png

Erhalten Sie das erste Token und speichern Sie das lange Kennwort, das auf dem Bildschirm angezeigt wird. Das Ablaufdatum des Tokens beträgt bis zu 12 Stunden und kann verkürzt werden, aber es scheint, dass es nicht länger sein kann. Ein wenig unpraktisch ...

Versuchen Sie es in einem Maven-Projekt

Lassen Sie uns die folgende Bibliothek im Maven-Projekt erstellen.

Bibliotheksspeicher

Greeting.java

Greeting.java


package com.amazonaws.lambda.demo;

public class Greeting {
    private String greetings;
    private String name = null;
	private String version = null;

    public String getGreetings() {
        return greetings;
    }
	public void setGreetings(String greetings) {
        this.greetings = greetings;
    }
    public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getVersion() {
		return version;
	}
	public void setVersion(String version) {
		this.version = version;
	}

    public Greeting(String greetings, String name, String version) {
		this.greetings = greetings;
		
		if(name != null) {
			this.name = name;
		}
		if(version != null) {
			this.version = version;
		}
		else {
			this.version = "1.0";
		}
	}
}
pom.xml

pom.xml


<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.amazonaws.lambda</groupId>
  <artifactId>Greeting</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <name>Greeting</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
          <forceJavacCompilerUse>true</forceJavacCompilerUse>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <distributionManagement>
    <repository>
      <id>test-domain-TestRepository</id>
      <name>test-domain-TestRepository</name>
      <url>[Repository-URL]</url>
    </repository>
  </distributionManagement>
</project>
settings.xml

settings.xml


<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <servers>
    <server>
      <id>test-domain-TestRepository</id>
      <username>aws</username>
      <password>[↑ Token werden durch den Erwerb von Token ausgezahlt]</password>
    </server>
  </servers>
</settings>

Nun, wenn Sie mvn bereitstellen und damit Erfolg haben ...

キャプチャ6.png

Das Repository wurde erfolgreich hinzugefügt!

Nutzung der Bibliothek

Der Code auf der Benutzerseite sollte wie folgt aussehen. settings.xml kann mit ↑ identisch sein. Es soll mit Lambda funktionieren, also macht es etwas Seltsames.

In der Handlerfunktion von Lambda der in der Bibliothek von ↑ definierten Klasse

Greeting greetingBody = new Greeting("Hello", "Taro", null);

Benutzt.

LambdaFunctionHandler.java

LambdaFunctionHandler.java


package com.amazonaws.lambda.demo;

import java.util.logging.Logger;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.LambdaLogger;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import java.util.Map;
import java.util.HashMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class LambdaFunctionHandler implements RequestHandler<Map<String, Object> , Response> {
	private static final Logger LOG = Logger.getLogger(LambdaFunctionHandler.class.getName());

    @Override
    public Response handleRequest(Map<String, Object> input, Context context) {
    	LambdaLogger logger = context.getLogger();
    	logger.log("received: " + input);

        Greeting greetingBody = new Greeting("Hello", "Taro", null);
        
        // TODO: implement your handler	
        return new Response.Builder()
        		.setStatusCode(200)
        		.setHeaders(new HashMap<String, String>(){{put("Content-Type","application/json");}})
        		.setObjectBody(greetingBody)
        		.build();
    }

}

Response.java

Response.java


package com.amazonaws.lambda.demo;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;

//import org.apache.log4j.Logger;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonInclude;


public class Response {
	private final int statusCode;
	private final Map<String, String> headers;
	private final boolean isBase64Encoded;
	private final String body;
		
	public int getStatusCode() {
		return statusCode;
	}

	public String getBody() {
		return body;
	}

	public Map<String, String> getHeaders() {
		return headers;
	}

	// API Gateway expects the property to be called "isBase64Encoded" => isIs
	public boolean isIsBase64Encoded() {
		return isBase64Encoded;
	}

	public static Builder builder() {
		return new Builder();
	}

	public static class Builder {
//		private static final Logger LOG = Logger.getLogger(Response.Builder.class);

		private static final ObjectMapper objectMapper = new ObjectMapper()
				.setSerializationInclusion(JsonInclude.Include.NON_NULL)
				.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

		private int statusCode = 200;
		private Map<String, String> headers = Collections.emptyMap();
		private String rawBody;
		private Object objectBody;
		private byte[] binaryBody;
		private boolean base64Encoded;

		public Builder setStatusCode(int statusCode) {
			this.statusCode = statusCode;
			return this;
		}

		public Builder setHeaders(Map<String, String> headers) {
			this.headers = headers;
			return this;
		}

		/**
		 * Builds the {@link Response} using the passed raw body string.
		 */
		public Builder setRawBody(String rawBody) {
			this.rawBody = rawBody;
			return this;
		}

		/**
		 * Builds the {@link Response} using the passed object body
		 * converted to JSON.
		 */
		public Builder setObjectBody(Object objectBody) {
			this.objectBody = objectBody;
			return this;
		}

		/**
		 * Builds the {@link Response} using the passed binary body
		 * encoded as base64. {@link #setBase64Encoded(boolean)
		 * setBase64Encoded(true)} will be in invoked automatically.
		 */
		public Builder setBinaryBody(byte[] binaryBody) {
			this.binaryBody = binaryBody;
			setBase64Encoded(true);
			return this;
		}

		/**
		 * A binary or rather a base64encoded responses requires
		 * <ol>
		 * <li>"Binary Media Types" to be configured in API Gateway
		 * <li>a request with an "Accept" header set to one of the "Binary Media
		 * Types"
		 * </ol>
		 */
		public Builder setBase64Encoded(boolean base64Encoded) {
			this.base64Encoded = base64Encoded;
			return this;
		}

		public Response build() {
			String body = null;
			if (rawBody != null) {
				body = rawBody;
			} else if (objectBody != null) {
				try {
					body = objectMapper.writeValueAsString(objectBody);
				} catch (JsonProcessingException e) {
//					LOG.error("failed to serialize object", e);
					throw new RuntimeException(e);
				}
			} else if (binaryBody != null) {
				body = new String(Base64.getEncoder().encode(binaryBody), StandardCharsets.UTF_8);
			}
			return new Response(statusCode, headers, base64Encoded, body);
		}
	}
	
    public Response(int statusCode, Map<String, String> headers, boolean isBase64Encoded, String body) {
    	this.statusCode = statusCode;
    	this.headers = headers;
    	this.isBase64Encoded = isBase64Encoded;
        this.body = body;
    }
}

Der Schlüssel ist der folgende Teil von pom.xml. Definition der in CodeArtifact gespeicherten Bibliotheksabhängigkeiten und Verbindungseinstellungen.

    <dependency>
      <groupId>com.amazonaws.lambda</groupId>
      <artifactId>Greeting</artifactId>
      <version>1.0.0</version>
    </dependency>
  <profiles>
    <profile>
      <id>test-domain-TestRepository</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <repositories>
        <repository>
          <id>test-domain-TestRepository</id>
          <name>test-domain-TestRepository</name>
          <url>[Repository-URL]</url>
        </repository>
      </repositories>
    </profile>
  </profiles>
pom.xml

pom.xml


<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.amazonaws.lambda</groupId>
  <artifactId>LambdaTest3</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <name>LambdaTest3</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <profiles>
    <profile>
      <id>test-domain-TestRepository</id>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>
      <repositories>
        <repository>
          <id>test-domain-TestRepository</id>
          <name>test-domain-TestRepository</name>
          <url>[Repository-URL]</url>
        </repository>
      </repositories>
    </profile>
  </profiles>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.6.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
          <forceJavacCompilerUse>true</forceJavacCompilerUse>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-bom</artifactId>
        <version>1.11.256</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-events</artifactId>
      <version>1.3.0</version>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-core</artifactId>
      <version>1.1.0</version>
    </dependency>
    
    <dependency>
      <groupId>com.amazonaws.lambda</groupId>
      <artifactId>Greeting</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
</project>

Wenn Sie nun ein mvn-Paket erstellen, wird die Bibliothek fest importiert und der Build ist abgeschlossen. Wenn Sie settings.xml vom Standardpfad geändert haben, müssen Sie die Option `` `-s``` angeben.

Versuchen Sie es in einem Gradle-Projekt

Lassen Sie uns nun portieren, was mit Maven mit Gradle Build erstellt wurde. Ändern Sie nicht den Inhalt der Java-Quelle.

Bibliotheksspeicher

Erstellen Sie das folgende build.gradle und `` `gradlew Publish```.

build.gradle


plugins {
    id 'maven-publish'
    id 'java-library'
}

repositories {
    jcenter()
}

dependencies {
    testImplementation 'junit:junit:4.12'
}

publishing {
  publications {
      mavenJava(MavenPublication) {
          groupId = 'com.amazonaws.lambda'
          artifactId = 'Greeting'
          version = '1.0.1'
          from components.java
      }
  }
  repositories {
      maven {
          url '[Repository-URL]'
          credentials {
              username "aws"
              password "[↑ Token werden durch den Erwerb von Token ausgezahlt]"
          }
      }
  }
}

Der folgende Fehler wird angezeigt, aber der Upload selbst scheint zu funktionieren.

> Task :publishMavenJavaPublicationToMavenRepository
Cannot upload checksum for module-maven-metadata.xml. Remote repository doesn't support sha-512. Error: Could not PUT 'https://test-domain-xxxxxxxxxxx.d.codeartifact.ap-northeast-1.amazonaws.com/maven/TestRepository/com/amazonaws/lambda/Greeting/maven-metadata.xml.sha512'. Received status code 400 from server: Bad Request

Nutzung der Bibliothek

Der Bibliotheksbenutzer legt build.gradle wie folgt fest. Wie bei der Bibliothek muss die Java-Quelle nicht geändert werden.

Um FatJar zu erstellen, führen Sie es mit `gradlew shadowJar``` anstelle von` gradle build``` aus.

build.gradle



plugins {
    id 'com.github.johnrengelman.shadow' version '2.0.3'
    id 'java-library'
}

repositories {
    jcenter()

    maven {
        url '[Repository-URL]'
        credentials {
            username "aws"
            password "[↑ Token werden durch den Erwerb von Token ausgezahlt]"
        }
    }
}

dependencies {
    implementation platform('com.amazonaws:aws-java-sdk-bom:1.11.256')
    implementation 'com.amazonaws:aws-lambda-java-events:1.3.0'
    implementation 'com.amazonaws:aws-lambda-java-core:1.1.0'
    runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.2.0'
    implementation 'com.amazonaws.lambda:Greeting:1.0.0'

    testImplementation 'junit:junit:4.12'
}

jar {
    manifest {
        attributes "Main-Class" : "LambdaFunctionHandler.java"
    }
}

Es kann bestätigt werden, dass es nicht nur mit Maven, sondern auch mit Gradle funktioniert.

Sie möchten CI / CD sogar eine gemeinsam genutzte Bibliothek

Ich weiß nicht, ob es eine Anfrage gibt. Natürlich kann Code Artifact auch in Code Build integriert werden.

Die Integration mit CodeBuild wird in Dieser Abschnitt des Benutzerhandbuchs beschrieben. Fügen Sie der CodeBuild-Servicerolle zum Veröffentlichen die folgenden Berechtigungen hinzu.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codeartifact:GetAuthorizationToken",
                "codeartifact:ReadFromRepository",
                "codeartifact:GetRepositoryEndpoint",
                "codeartifact:PublishPackageVersion",
                "codeartifact:PutPackageMetadata",
                "sts:GetServiceBearerToken"
            ],
            "Resource": "*"
        }
    ]
}

Der Punkt ist buildspec.yml, aber vorher wollen wir die settings.xml überprüfen, die wir dieses Mal erstellt haben. Es ist nicht so sehr so, dass Sie das Token jedes Mal manuell abrufen müssen, wenn Sie CI / CI aktivieren. Machen Sie also das `` `password``` -Tag wie folgt.

      <password>${env.CODEARTIFACT_TOKEN}</password>

Definieren wir dann buildspec.yml wie folgt. Übrigens funktioniert der Teil `aws codeartifact``` nicht, wenn Sie ihn wie im Benutzerhandbuch beschrieben ausführen. Beachten Sie, dass es ohne `--query authorisationToken``` nicht funktioniert. Diese Option ist nicht einmal in der CLI-Dokumentation aufgeführt (https://docs.aws.amazon.com/cli/latest/reference/codeartifact/get-authorization-token.html), was ein ziemliches Rätsel ist ... .. Wenn diese Option nicht hinzugefügt wird, wird vorerst der Zeitstempel ausgegeben und es handelt sich nicht um die erwartete Umgebungsvariable.

buildspec.yml


version: 0.2
 
phases:
  install:
    runtime-versions:
      java: corretto8
    commands:
      - pip install --upgrade pip
      - pip install --upgrade awscli
  pre_build:
    commands:
      - export CODEARTIFACT_TOKEN=$(aws codeartifact get-authorization-token --domain test-domain --domain-owner [Konto-ID] --query authorizationToken --output text)
  build:
    commands:
      - echo Build started on `date`
      - mvn -s ./settings.xml deploy
      - echo Build ended on `date`
cache:
  paths:
    - '/root/.m2/**/*'

Die CI / CD-Pipeline der Bibliothek ist jetzt abgeschlossen!

Recommended Posts

Versuchen Sie, Java-Bibliotheken mit AWS CodeArtifact zu verwalten
Versuchen Sie eine DB-Verbindung mit Java
Versuchen Sie gRPC mit Java, Maven
Versuchen Sie es mit Redis mit Java (jar)
Verwenden von Java mit AWS Lambda-Eclipse-Vorbereitung
Versuchen Sie die bidirektionale Kommunikation mit gRPC Java
Versuchen Sie, AWS X-Ray in Java auszuführen
Java-Bibliotheken
Verwenden von Java mit AWS Lambda-Implementation-Check CloudWatch-Argumenten
Verwenden von Java mit AWS Lambda-Implementierung-Stop / Launch EC2
Probieren wir WebSocket mit Java und Javascript aus!
Versuchen Sie es mit der Wii-Fernbedienung in Java
Probieren Sie Java 8 Stream aus
Versuchen Sie, Ruby und Java in Dapr zu integrieren
Verwendung des Java-Frameworks mit AWS Lambda! ??
Versuchen Sie, TCP / IP + NIO mit JAVA zu implementieren
Versuchen Sie es mit Java 9
Versuchen Sie, ein Java-Programm mit VS-Code zu debuggen
Senden Sie einen Job an AWS Batch mit Java (Eclipse)
So stellen Sie Java mit Serverless Framework für AWS Lambda bereit
Versuchen Sie, mit Java eine Verbindung zu AzureCosmosDB Emulator for Docker herzustellen
Versuchen Sie, Java mit GraalVM in ein natives Modul zu integrieren
Versuchen Sie DI mit Micronaut
Installieren Sie Java mit Homebrew
Versuchen Sie es mit Trailblazer
Wechseln Sie die Plätze mit Java
Installieren Sie Java mit Ansible
Probieren Sie WebSocket mit Jooby aus
Schalten Sie Java mit direnv
Java-Download mit Ansible
Lass uns mit Java kratzen! !!
Erstellen Sie Java mit Wercker
Versuchen Sie es mit dem Java-Rückgabewert
Endian-Konvertierung mit JAVA
Veröffentlichen Sie regelmäßig Bild-Tweets auf Twitter mit AWS Lambda + Java
Protokollaggregation und -analyse (Arbeiten mit AWS Athena in Java)
[Anfänger] Versuchen Sie, mit Java ein einfaches RPG-Spiel zu erstellen ①
Erstellen Sie einen SlackBot mit AWS Lambda & API Gateway in Java
Versuchen Sie Spark Submit to EMR mit AWS SDK für Java