Jusqu'à ce que l'objet S3 soit INSERT dans EC2 DB avec Lambda @ java: Java [Suite]

introduction

Cet article rappelle ce qu'AWS, java (presque) débutants ont fait avant d'insérer des objets S3 dans la base de données d'EC2 (SQL Server) avec Lambda @ java. Il s'agit de la dernière édition de la première trilogie post (+ α). Si vous faites remarquer que c'est mieux ici, s'il vous plaît! !!

1: Édition AWS 2: Java [Partie 1] 3: Java [Partie 2] 3.5: Java [suite] <-Main

Rôles Lambda et paramètres réseau

Paramètres de rôle IAM

Avant de modifier la source à l'étape finale, configurons Lambda. Lorsque Lambda accède à d'autres services tels que EC2 et RDS dans le VPC, la fonction elle-même exécutée par Lambda doit également appartenir au VPC. Pour cela, il est nécessaire de définir le rôle IAM, etc., mais une fois terminé, le rôle qui permet d'accéder au VPC lorsque Lambda détecte un événement déclencheur, ENI (Elastic Network Interface) Étant donné que //docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-eni.html) est automatiquement attribué, les fonctions Lambda peuvent accéder aux ressources du VPC. Je vais. (Plus vous en savez, mieux AWS est ...)

Note) La version source doit être mssql-jdbc-7.0.0.jre8.jar.

Dans la console de gestion Lambda, sélectionnez le lambda_s3_exec_role créé et ajoutez une stratégie. Ajoutons une stratégie, "AWSLambdaVPCAccessExecutionRole", pour accéder aux ressources dans le VPC. Si le droit d'accès à CloudWatch Logs est également joint et saisi, la préparation est terminée.

paramètres réseau

Ouvrez la console Lambda, définissez l'environnement d'exécution sur Java8 et créez une nouvelle fonction. Ouvrez la page des détails de la fonction et définissez le rôle d'exécution sur lambda_s3_exec_role. 01_lambda_exec_role.png Ensuite, dans [Réseau], sélectionnez "test_vpc" créé dans l'édition AWS (pour être exact, sélectionnez "VPC auquel appartient la ressource ciblée pour l'action", comme EC2 ou RDS). * 1 Cela entraînera l'appartenance de la fonction Lambda au VPC et émettra une ENI. En outre, sélectionnez le sous-réseau et le groupe de sécurité appropriés. 02_lambda_network.png Après avoir terminé les paramètres réseau, enregistrez les paramètres de fonction.

Mise en garde

Il y a une partie à prendre en compte ici.

Pour accéder aux ressources (EC2, RDS, etc.) dans le VPC, il était nécessaire d'enregistrer la fonction Lambda dans le VPC comme dans le flux précédent. Cependant, une fois que la fonction Lambda devient une ressource au sein du VPC, elle ne pourra plus accéder aux services en dehors du VPC (S3, Kinesis, etc.).

Veuillez vous référer à l'article suivant pour plus de détails. Comment accéder aux services externes de Lambda dans VPC

Pour éviter cela,

--Création d'une passerelle NAT --Créer un point de terminaison

Il y en a, mais cette fois c'est facile, je voudrais donc procéder au réglage avec ce dernier.

Créer un point de terminaison

Sélectionnez "Endpoint" dans la barre de navigation de la console de gestion VPC et cliquez sur Créer un point de terminaison. Étant donné que l'accès à un autre que S3 n'est pas requis cette fois, l'état sera le suivant. 03_create_endpoint.png Ensuite, sélectionnez le VPC. Vous pouvez sélectionner la table de routage en sélectionnant le VPC auquel appartient la fonction Lambda ou l'instance EC2. Si vous avez plusieurs tables de routage, choisissez la bonne. 04_create_endpoint02.png

À ce stade, les réglages sont presque terminés. Le diagramme de configuration AWS qui résume les modifications apportées jusqu'à présent est le suivant.

05_AWS_network.png 1. EC2 appartient à VPC et se trouve dans un sous-réseau. EIP est également attribué. 2. Lambda appartient au même sous-réseau que EC2. 3. Endpoint est utilisé pour établir la communication entre Lambda à l'intérieur du VPC et S3 à l'extérieur du VPC. 4. Le point de terminaison est défini dans la table de routage du sous-réseau auquel appartiennent EC2 et Lambda.

Modifier la source

Maintenant, confirmons à nouveau que "la fonction Lambda peut être exécutée et le fichier correspondant peut être lu en utilisant le téléchargement du fichier CSV vers S3 comme déclencheur".

DetectS3Event.java


package lambdaTest.S3toLambda;

/*importation omise*/

public class DetectS3Event implements RequestHandler<S3Event, Object>
{
	LambdaLogger lambdaLogger = null;
	
    public AmazonS3 createS3Client() throws Exception
    {
    	AWSCredentials credentials = new BasicAWSCredentials("<accessKey>","<secretKey>");
    	AmazonS3 client = AmazonS3ClientBuilder.standard()
    						.withCredentials(new AWSStaticCredentialsProvider(credentials))
    						.build();
		return client;
    }

	@Override
	public Context handleRequest(S3Event event, Context context) {
		context.getLogger().log("Input: " + event);
		lambdaLogger = context.getLogger();
		
		// ===== get event information (S3 Put) =====
		S3EventNotificationRecord record = event.getRecords().get(0);
		String bucketName = record.getS3().getBucket().getName();		// s3 bucket name
		String key = record.getS3().getObject().getKey();				// s3 object key
		
		lambdaLogger.log("bucketName = " + bucketName);
		lambdaLogger.log("object key = " + key);
		
		try {
			AmazonS3 client = createS3Client();
			// Get target object of event
			S3Object object = client.getObject(new GetObjectRequest(bucketName, key));
			lambdaLogger.log("S3 client = " + client.toString());
			
			BufferedInputStream bis = new BufferedInputStream(object.getObjectContent());
			BufferedReader br = new BufferedReader(new InputStreamReader(bis));

			String line = "";
            // Output contents of object line by line
			while((line = br.readLine()) != null) {
				lambdaLogger.log(line);
			}
			
		} catch (IOException e) {
			lambdaLogger.log("IOException error message : " + e.getErrorMessage());
		} catch (AmazonServiceException e) {
			lambdaLogger.log("AWSException error message : " + e.getErrorMessage());
		} catch (Exception e) {
			lambdaLogger.log("Exception error message : " + e.getMessage());
		}
		
		return null;
	}
}

Après avoir créé le fichier ci-dessus, téléchargez le fichier jar fourni avec Maven, etc. sur Lambda.

Téléchargez le CSV suivant sur S3.

emp_values.csv


1001,Dean,28
1002,Sam,25
1003,John,51
1004,Bobby,54
1005,Meg,26

Connectons-nous à CloudWatch et vérifions le journal. 06_lambda_executed.png Vous pouvez voir que le CSV ci-dessus est sorti dans le journal ligne par ligne.

Enfin, insérons ce CSV dans la base de données sur EC2.

INSÉRER dans DB

La base de données et la table sont la précédente [partie Java [Partie 2]](https://qiita.com/yut0201/items/0d955b37f1f461cce815#%E3%83%87%E3%83%BC%E3%82%BF%E3% 83% 99% E3% 83% BC% E3% 82% B9% E3% 81% 8A% E3% 82% 88% E3% 81% B3% E3% 83% A6% E3% 83% BC% E3% 82% Utilisez la table des employés LambdaTestDB créée dans B6% E3% 81% AE% E4% BD% 9C% E6% 88% 90).

Assurez-vous qu'il n'y a aucun enregistrement dans la table.

1> SELECT * FROM employee;
2> go
emp_id      emp_name             age        
----------- -------------------- -----------

(0 rows affected)

Maintenant, éditons la source.

DetectS3Event.java


package lambdaTest.S3toLambda;

/*importation omise*/

public class DetectS3Event implements RequestHandler<S3Event, Object>
{
	LambdaLogger lambdaLogger = null;
	
	Connection mssqlCon = null;
	
    public AmazonS3 createS3Client() throws Exception
    {
    	AWSCredentials credentials = new BasicAWSCredentials(
                							"<accessKey>",
    										"<secretKey>");
    	
    	AmazonS3 client = AmazonS3ClientBuilder.standard()
    						.withCredentials(new AWSStaticCredentialsProvider(credentials))
    						.build();
    	
		return client;
    }

	@Override
	public Context handleRequest(S3Event event, Context context) {
		context.getLogger().log("Input: " + event);
		lambdaLogger = context.getLogger();
		
		// ===== get event information (S3 Put) =====
		S3EventNotificationRecord record = event.getRecords().get(0);
		String bucketName = record.getS3().getBucket().getName();		// s3 bucket name
		String key = record.getS3().getObject().getKey();				// s3 object key
		
		lambdaLogger.log("bucketName = " + bucketName);
		lambdaLogger.log("object key = " + key);
		
		try {
			AmazonS3 client = createS3Client();
			
			S3Object object = client.getObject(new GetObjectRequest(bucketName, key));
			
			lambdaLogger.log("S3 client = " + client.toString());
			
			BufferedInputStream bis = new BufferedInputStream(object.getObjectContent());
			BufferedReader br = new BufferedReader(new InputStreamReader(bis));
			
			ResourceBundle sqlServerResource = ResourceBundle.getBundle("sqlServer");
			DatabaseInfo sqlServerInfo = new DatabaseInfo(sqlServerResource.getString("driver"),
											sqlServerResource.getString("url"),
											sqlServerResource.getString("user"),
											sqlServerResource.getString("pass"));
			
			/* ======== SQL Server connection ======== */
			lambdaLogger.log("SQL Server Session creating...");
			SqlServer sqlServer = new SqlServer();
			mssqlCon = sqlServer.openConnection(sqlServerInfo);
			lambdaLogger.log("SUCCESS : SQL Server session created !!");
			
			String line = "";
			Statement insertStmt = mssqlCon.createStatement();
			while((line = br.readLine()) != null) {
				String[] values = line.split(",");
				String insertRecord = "INSERT INTO employee VALUES("
										+ values[0] + ", '"
										+ values[1] + "', "
										+ values[2] + ");";
				insertStmt.executeUpdate(insertRecord);
			}
			
			if (insertStmt != null) insertStmt.close();
	        if (mssqlCon != null) sqlServer.closeConnection(mssqlCon);
	        if (br != null) br.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (AmazonServiceException e) {
			lambdaLogger.log("Error message : " + e.getErrorMessage());
		} catch (Exception e) {
			lambdaLogger.log("Exception error message : " + e.getMessage());
		}
		
		return null;
	}
}

Dans l'instruction while, les CSV lus ligne par ligne sont disposés dans un tableau séparé par des virgules, et chacun est INSERT comme valeur de chaque colonne de l'enregistrement. Vous aurez besoin d'une connexion pour vous connecter à la base de données, alors créez un nouveau fichier ci-dessous.

SqlServer.java


package lambdaTest.db;

/*importation omise*/

public class SqlServer {
	
	public SqlServer() {
		super();
	}
	
	public Connection openConnection(DatabaseInfo dbInfo)
    {
		Connection con = null;
		
        try {
        	Class.forName(dbInfo.getDriver());
	        
	        con = DriverManager.getConnection(dbInfo.getUrl(), dbInfo.getDbUser(), dbInfo.getDbPass());
        	
		} catch (SQLException | ClassNotFoundException e) {
			System.out.println("anything Exception : " + e);
		}
		return con;
    }

	public void closeConnection(Connection con) {
		try {
			con.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
	}
}

Déléguez la gestion des connexions à la base de données à cette classe. Il n'y a aucun problème avec le codage en dur pour chaque paramètre requis pour la connexion tel que l'URL de connexion, le nom d'utilisateur, le mot de passe, etc. Mettez-le sous forme de fichier de propriétés en mettant l'accent sur la réutilisation

sqlServer.properties


driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
url=jdbc:sqlserver://<EC2-privateIP>:<portNo>;databaseName=<databaseName>
user=<userName>
pass=<password>

De plus, puisque vous avez besoin d'une classe pour lier le fichier de propriétés, créons également la classe suivante.

DatabaseInfo.java


package lambdaTest.S3toLambda;

final public class DatabaseInfo {
	String driver;
	String url;
	String dbUser;
	String dbPass;
	
	public String getDriver() {
		return driver;
	}

	public String getUrl() {
		return url;
	}

	public String getDbUser() {
		return dbUser;
	}

	public String getDbPass() {
		return dbPass;
	}
	
	public DatabaseInfo(String driver, String url, String dbUser, String dbPass) {
		this.driver = driver;
		this.url = url;
		this.dbUser = dbUser;
		this.dbPass = dbPass;
	}
}

Enfin, ajoutez quelques lignes à pom.xml afin que Maven puisse lire correctement le fichier de propriétés externes. Ici, seule la section de construction à ajouter est extraite et la ligne ajoutée est marquée d'une étoile.

pom.xml


<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.3</version>
        <configuration>
          <encoding>UTF-8</encoding>
          <createDependencyReducedPom>false</createDependencyReducedPom>
          <filters>
            <filter>
              <artifact>*:*</artifact>
              <excludes>
                <exclude>META-INF/*.SF</exclude>
                <exclude>META-INF/*.DSA</exclude>
                <exclude>META-INF/*.RSA</exclude>
              </excludes>
            </filter>
          </filters>
          <archive>
            <manifest>
              <mainClass>com.gmail.greencoffeemaker.MainApp</mainClass>
              <addClasspath>true</addClasspath>
            </manifest>
            <manifestEntries>
              <Class-Path>./src/resources/</Class-Path>
            </manifestEntries>
          </archive>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
                        <!--Partie Postscript-->
            <configuration>
              <target>
                <!--copie: /src/main/resources => /target/resources -->
                <mkdir dir="${project.build.directory}/resources" />
                <copy todir="${project.build.directory}/resources">
                  <fileset dir="${project.basedir}/src/main/resources" />
                </copy>
              </target>
            </configuration>
                        <!--Jusque là-->
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

La modification est maintenant terminée. Après la construction, téléchargez le fichier jar sur Lambda et placez à nouveau emp_values.csv dans S3.

Lorsque je me connecte à SQL Server sur EC2 et que je regarde le tableau. .. ..

1> SELECT * FROM employee;
2> go
emp_id      emp_name             age        
----------- -------------------- -----------
       1001 Dean                          28
       1002 Sam                           25
       1003 John                          51
       1004 Bobby                         54
       1005 Meg                           26

(5 rows affected)

** C'est fait! !! !! ** **

Résumé

Cela fait quelques années que j'ai touché Java pour la première fois en écrivant cet article et AWS est le premier La préparation était quasiment nulle, mais j'étais soulagé de pouvoir faire ce que je voulais faire. Lire le manuel, rechercher des connaissances, etc., le temps de travail par jour était inférieur à 3 heures et le sentiment de travail était d'environ 2 semaines. Je pense que l'essentiel du travail consistait à éviter les erreurs trébuchantes en cours de route.

Je veux améliorer l'efficacité du travail. Désespéré.

Recommended Posts

Jusqu'à ce que l'objet S3 soit INSERT dans EC2 DB avec Lambda @ java: Java [Suite]
Jusqu'à INSERT S3 objet dans EC2 DB avec Lambda @ java: AWS
Jusqu'à ce que l'objet S3 soit INSERT dans EC2 DB avec Lambda @ java: Java [Partie 2]
Jusqu'à INSERT S3 objet dans EC2 DB avec Lambda @ java: Java [Partie 1]
[Java] Les insertions Batch Insert sont combinées en une seule lorsque vous utilisez MySQL DB dans Doma.
Essayez la connexion DB avec Java
Connectez-vous à DB avec Java