[DOCKER] [Java] De la création d'un nouveau projet à la réalisation automatique de test / construction / déploiement

TL;DR Automatiquement lorsque des modifications sont apportées à la branche git

Construisez un projet Java à partir de zéro

Ce qui apparaît

OSS

un service

Mise en œuvre d'un exemple de projet

Enfin, la structure des répertoires ressemble à ceci. Je vais le faire étape par étape. Vous pouvez également cloner depuis GitHub.

testproject/
    ├ src/
    │   ├ main/
    │   │   └ java/
    │   │        └testpackage/
    │   │            └Main.java
    │   └ test/
    │       └ java/
    │           └testpackage/  
    │              └MainTest.java   
    ├ .cifcleci/
    │   └ config.yml
    ├ schema.sql
    ├ pom.xml
    ├ deploy.yaml
    └ Dockerfile

1. Définition du schéma

Décrivez le schéma de la table. Vous pouvez le mettre dans le dossier de ressources, mais cette fois, je vais le mettre dans le répertoire supérieur. Aucun nom de base de données n'est spécifié.

schema.sql


CREATE TABLE user (id int, name varchar(10));

2. Créer un projet maven

Implémentez un projet Java minimal qui insère les enregistrements appropriés dans le tableau ci-dessus.

Utilisez JDBC, JUnit, maven-assembly-plugin.

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>aaaanwz</groupId>
	<artifactId>test</artifactId>
	<version>0.0.1</version>
	<name>testproject</name>
	<properties>
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
	</properties>
	<dependencies>
		<!-- JDBC driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.17</version>
		</dependency>
		<!-- JUnit -->
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>5.3.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- JUnit test -->
			<plugin>
				<artifactId>maven-surefire-plugin</artifactId>
				<version>3.0.0-M3</version>
			</plugin>
			<!-- Build runnable jar -->
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<archive>
						<manifest>
							<mainClass>testpackage.Main</mainClass>
						</manifest>
					</archive>
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					</descriptorRefs>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Implémentez la classe Main qui n'insère qu'un seul enregistrement. Les informations de connexion à la base de données sont obtenues à partir de la variable d'environnement.

src/main/java/testpackage/Main.java


package testpackage;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Main {

  public static void main(String[] args) throws ClassNotFoundException, SQLException {
    final String host = System.getenv("DB_HOST");
    final String dbname = System.getenv("DB_NAME");
    execute(host, dbname);
  }

  static void execute(String host, String dbname) throws ClassNotFoundException, SQLException {
    Class.forName("com.mysql.cj.jdbc.Driver");
    Connection conn = DriverManager.getConnection(
        "jdbc:mySql://" + host + "/" + dbname + "?useSSL=false", "root", "");
    PreparedStatement stmt = conn.prepareStatement("INSERT INTO user(id,name) VALUES(?, ?)");
    stmt.setInt(1, 1);
    stmt.setString(2, "Yamada");
    stmt.executeUpdate();
  }

}

Écrivez un test qui confirme simplement que l'enregistrement a été inséré.

src/test/java/testpackage/MainTest.java


package testpackage;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import testpackage.Main;

class MainTest {
  Statement stmt;

  @BeforeEach
  void before() throws ClassNotFoundException, SQLException {
    Class.forName("com.mysql.cj.jdbc.Driver");
    Connection conn =
        DriverManager.getConnection("jdbc:mySql://localhost/test?useSSL=false", "root", "");
    stmt = conn.createStatement();
  }

  @AfterEach
  void after() throws SQLException {
    stmt.executeUpdate("TRUNCATE TABLE user");
  }

  @Test
  void test() throws Exception {
    Main.execute("localhost", "test");
    try (ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE id = 1;")) {
      if (rs.next()) {
        assertEquals("Yamada", rs.getString("name"));
      } else {
        fail();
      }
    }
  }
}

3. Créez Dockerfile

Écrivez un Dockerfile. Étant donné que les tests seront effectués dans une étape distincte de la construction du docker, ajoutez -DskipTests pour ignorer les tests de construction.

Pour réduire la taille de l'image, nous allons construire avec maven: 3.6 et la construction en plusieurs étapes avec openjdk11: append-slim. C'est environ 800 Mo pour maven: 3,6 et environ 300 Mo pour openjdk11: alpine-slim. Pour le moment, le niveau gratuit d'ECR est de 500 Mo, ce qui est une grande différence pour le développement personnel.

Dockerfile


FROM maven:3.6 AS build

ADD . /var/tmp/testproject/
WORKDIR /var/tmp/testproject/
RUN mvn -DskipTests package

FROM adoptopenjdk/openjdk11:alpine-slim

COPY --from=build /var/tmp/testproject/target/test-0.0.1-jar-with-dependencies.jar /usr/local/
CMD java -jar /usr/local/test-0.0.1-jar-with-dependencies.jar.jar

4. Créez un fichier yaml k8s

Écrivez yaml pour déployer le conteneur 3. intégré dans k8s. Puisque ce programme exécute SQL en un seul coup et se termine, essayez d'utiliser kind: Job. Remplacez l'url dans le registre Docker comme il convient. Définissez les informations de connexion à la base de données avec ʻenv. La valeur de DB_HOST est mysql` car il se connecte via le service Kubernetes.

k8s-job.yaml


apiVersion: batch/v1
kind: Job
metadata:
  name: test
spec:
  template:
    spec:
      containers:
      - name: test
        image: your-docker-registry-url/testimage:latest
        imagePullPolicy: Always
        env:
        - name: DB_HOST
          value: "mysql"
        - name: DB_NAME
          value: "ekstest"
      restartPolicy: Never
  backoffLimit: 0

5. Créez le fichier de configuration de circleci

C'est la clé de cet article. Écrivez les paramètres de configuration pour les tests / la construction automatisés avec CircleCI.

yml:.circleci/config.yml


version: 2.1
orbs:
  aws-ecr: circleci/[email protected]
  aws-eks: circleci/[email protected]
  kubernetes: circleci/[email protected]
jobs:
  test: #① Exécutez le test JUnit
    docker:
      - image: circleci/openjdk:11
      - image: circleci/mysql:5.7
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_DATABASE: test
        command: [--character-set-server=utf8, --collation-server=utf8_general_ci, --default-storage-engine=innodb]
    steps:
      - checkout
      - run:
          name: Waiting for MySQL to be ready
          command: dockerize -wait tcp://localhost:3306 -timeout 1m
      - run:
          name: Install MySQL CLI; Create table;
          command: sudo apt-get install default-mysql-client && mysql -h 127.0.0.1 -uroot test < schema.sql
      - restore_cache:
          key: circleci-test-{{ checksum "pom.xml" }}
      - run: mvn dependency:go-offline
      - save_cache:
          paths:
            - ~/.m2
          key: circleci-test-{{ checksum "pom.xml" }}
      - run: mvn test
      - store_test_results:
          path: target/surefire-reports
  deploy: #③ kubectl s'appliquent à EKS
    executor: aws-eks/python3
    steps:
      - checkout
      - kubernetes/install
      - aws-eks/update-kubeconfig-with-authenticator:
          cluster-name: test-cluster
          aws-region: "${AWS_REGION}"
      - run:
          command: |
            kubectl apply -f k8s-job.yaml
          name: apply
workflows:
  test-and-deploy:
    jobs: 
      - test: #① Exécutez le test JUnit
          filters:
            branches:
              only: develop
      - aws-ecr/build-and-push-image: #② Construisez le conteneur et poussez vers ECR
          filters:
            branches:
              only: master
          create-repo: true
          repo: "testimage"
          tag: "latest"
      - deploy: #③ kubectl s'appliquent à EKS
          requires:
            - aws-ecr/build-and-push-image

① Exécution du test JUnit

J'ai essayé de faire fonctionner le mvn test quand un changement est apporté à la branche develop par filtre. A ce moment, une instance de test MySQL est lancée et la base de données test est préparée.

Il est expliqué en détail dans le document officiel.

② Construisez le conteneur et poussez vers ECR

Lorsque des modifications sont apportées à la branche master, construisez selon le Dockerfile et poussez vers ECR. Il est expliqué en détail dans le Guide de démarrage rapide d'Orb.

③ kubectl s'appliquent à EKS

Une fois ② exécuté, le Job défini en 4. est exécuté. Il y a une explication dans circleci / aws-eks, mais l'exemple de code a été modifié pour être plus simple. D'après la documentation de @ 0.2.1, le paramètre ʻaws-region n'est pas obligatoire, mais il semble être nécessaire dans la pratique. La variable d'environnement ʻAWS_REGION est demandée par push d'ECR, donc je l'ai utilisée telle quelle.

Paramètres d'infrastructure

Surtout une collection de liens vers des documents officiels.

1. Préparation environnementale ECR, EKS

1-1. Paramètres de base

Lancez test-cluster.

1-2. Déployer MySQL sur EKS

Kubernetes a officiellement un document appelé Deploy MySQL. Préparez la base de données ʻekstest et la table ʻuser à partir de la commande kubectl exec -it mysql-0 mysql.

2. Paramètres du projet CircleCI

2-1. Configuration du projet

2-2. Définition des variables d'environnement

Résumé

--pousser pour développer une branche Le test mvn est exécuté et le rapport de test s'affiche dans le résumé du test CircleCI. --pousser vers la branche principale L'image du docker est poussée vers ECR et le travail démarre à EKS. Un enregistrement ʻid: 1 name: Yamada` est inséré dans MySQL sur EKS.

Qu'as-tu pensé. J'espère que vous essaierez diverses choses, comme abandonner volontairement le test.

Recommended Posts

[Java] De la création d'un nouveau projet à la réalisation automatique de test / construction / déploiement
Nouvelles fonctionnalités de Java7 à Java8
Création automatique du rapport de résultat du test unitaire Java
Changements de Java 8 à Java 11
Somme de Java_1 à 100
Eclipse ~ Création de projet Java ~
De Java à Ruby !!
Découvrez les nouvelles fonctionnalités de Java 7 à Java 9 à la fois
Migration de Cobol vers JAVA
Connectez-vous de Java à PostgreSQL
De Java inefficace à Java efficace
Comment créer un nouveau projet Gradle + Java + Jar dans Intellij 2016.03
[Gradle] Construisez un projet Java avec une configuration différente de la convention
Construire un projet Java avec Gradle
Java sera impliqué dès aujourd'hui
De Java à VB.NET - Écriture de notes de contraste
Java, interface pour partir du débutant
Accro à l'importation de projets depuis GitHub
La route de JavaScript à Java
[Java] Conversion d'un tableau à une liste
Passer de SQLite3 à PostgreSQL dans un nouveau projet Ruby on Rails