example deploy application java mysql spring spring-mvc openshift

java - deploy - Usando la variable env en la aplicación Spring Boot.



openshift deploy java application (8)

Estamos trabajando en una aplicación web Spring Boot y la base de datos que estamos usando es MySql ;

  • la configuración que tenemos es que primero lo probamos localmente (significa que necesitamos instalar MySql en nuestra PC);

  • luego empujamos a Bitbucket ;

  • Jenkins detecta automáticamente el nuevo impulso a Bitbucket y lo construye (para que pase la compilación mvn de Jenkins también necesitamos instalar MySql en las máquinas virtuales que ejecutan Jenkins).

  • si la compilación de Jenkins pasa, enviamos el código a nuestra aplicación en OpenShift (usando el complemento de implementación Openshift en Jenkins).

El problema que tenemos, ya que quizás ya lo haya resuelto, es que:

  • en application.properties no podemos codificar la información de MySql. Dado que nuestro proyecto se ejecutará en 3 lugares diferentes ( local , Jenkins y OpenShift ), necesitamos que el campo del origen de datos sea dinámico en application.properties (sabemos que hay diferentes formas de hacerlo, pero estamos trabajando en esta solución por ahora) .

    spring.datasource.url = spring.datasource.username = spring.datasource.password =

La solución que se nos ocurrió es que creamos variables de entorno del sistema localmente y en la máquina virtual de Jenkins (nombrándolas de la misma manera que OpenShift las nombra) y asignándoles los valores correctos, respectivamente:

export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost" export OPENSHIFT_MYSQL_DB_PORT="3306" export OPENSHIFT_MYSQL_DB_USERNAME="root" export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"

Hemos hecho esto y funciona. También hemos verificado con Map<String, String> env = System.getenv(); que las variables de entorno se pueden convertir en variables java como tales:

String password = env.get("OPENSHIFT_MYSQL_DB_PASSWORD"); String userName = env.get("OPENSHIFT_MYSQL_DB_USERNAME"); String sqlURL = env.get("OPENSHIFT_MYSQL_DB_HOST"); String sqlPort = env.get("OPENSHIFT_MYSQL_DB_PORT");

Ahora lo único que queda es que necesitamos usar estas variables de Java en nuestra application.properties y eso es con lo que estamos teniendo problemas.

¿En qué carpeta y cómo debemos asignar las variables de password , nombre de password , sqlURL y sqlPort para application.properties para poder verlas y cómo las incluimos en application.properties ?

Hemos probado muchas cosas, una de ellas es:

spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB" spring.datasource.username = ${userName} spring.datasource.password = ${password}

Sin suerte hasta ahora. Probablemente no estamos colocando estas variables env en la clase / carpeta correcta o las estamos usando incorrectamente en application.properties .

¡¡Tu ayuda es altamente apreciada!!

¡Gracias!


Esto es en respuesta a una serie de comentarios, ya que mi reputación no es lo suficientemente alta como para comentar directamente.

Puede especificar el perfil en tiempo de ejecución siempre que el contexto de la aplicación aún no se haya cargado.

// Previous answers incorrectly used "spring.active.profiles" instead of // "spring.profiles.active" (as noted in the comments). // Use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME to avoid this mistake. System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment); ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");


Flayway no reconoce las variables de entorno directas en application.properties (Spring-Boot V2.1). p.ej

spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE} spring.datasource.username=${DB_USER} spring.datasource.password=${DB_PASS}

Para resolver este problema, hice estas variables de entorno, generalmente creo el archivo .env:

SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place SPRING_DATASOURCE_USERNAME=root SPRING_DATASOURCE_PASSWORD=root

Y exportar las variables a mi entorno:

export $(cat .env | xargs)

Y finalmente solo ejecuta el comando

mvn spring-boot:run

O ejecuta tu archivo jar

java -jar target/your-file.jar

Hay otro enfoque aquí: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html


La forma más fácil de tener diferentes configuraciones para diferentes entornos es usar perfiles de resorte. Ver @ConfigurationProperties .

Esto te da mucha flexibilidad. Lo estoy usando en mis proyectos y es extremadamente útil. En su caso, tendría 3 perfiles: ''local'', ''jenkins'' y ''openshift''

Luego tiene 3 archivos de propiedades específicos del perfil: application-local.properties , application-jenkins.properties y application-openshift.properties

Allí puede establecer las propiedades para el entorno correspondiente. Cuando ejecuta la aplicación, debe especificar el perfil para activarlo de esta manera: -Dspring.profiles.active=jenkins

Editar

Según el documento de Spring, puede configurar la variable de entorno del sistema SPRING_PROFILES_ACTIVE para activar los perfiles y no es necesario pasarla como parámetro.

¿Hay alguna manera de pasar la opción de perfil activo para la aplicación web en tiempo de ejecución?

No. Spring determina los perfiles activos como uno de los primeros pasos, al construir el contexto de la aplicación. Los perfiles activos se utilizan para decidir qué archivos de propiedades se leen y qué beans se instancian. Una vez que se inicia la aplicación, esto no se puede cambiar.


Me enfrenté al mismo problema que el autor de la pregunta. Para nuestro caso, las respuestas en esta pregunta no fueron suficientes ya que cada uno de los miembros de mi equipo tenía un entorno local diferente y definitivamente necesitábamos .gitignore el archivo que tenía las diferentes cadenas y credenciales de conexión db, por lo que la gente no compromete archivo común por error y romper las conexiones db de otros.

Además de eso, cuando seguimos el siguiente procedimiento, fue fácil de implementar en diferentes entornos y, como beneficio adicional , no necesitábamos tener ninguna información confidencial en el control de versiones .

Obteniendo la idea del framework PHP Symfony 3 que tiene un parameters.yml (.gitignored) y un parameters.yml.dist (que es una muestra que crea el primero a través de la composer install ),

Hice lo siguiente combinando el conocimiento de las respuestas a continuación: https://.com/a/35534970/986160 y https://.com/a/35535138/986160 .

Esencialmente, esto le da la libertad de usar la herencia de las configuraciones de resorte y elegir los perfiles activos a través de la configuración en la parte superior más cualquier credencial extra sensible de la siguiente manera:

application.yml.dist (muestra)

spring: profiles: active: local/dev/prod datasource: username: password: url: jdbc:mysql://localhost:3306/db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application.yml (.gitignore-d en el servidor de desarrollo)

spring: profiles: active: dev datasource: username: root password: verysecretpassword url: jdbc:mysql://localhost:3306/real_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application.yml (.gitignore-d en la máquina local)

spring: profiles: active: local datasource: username: root password: rootroot url: jdbc:mysql://localhost:3306/xampp_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application-dev.yml (propiedades específicas del entorno adicionales no sensibles)

spring: datasource: testWhileIdle: true validationQuery: SELECT 1 jpa: show-sql: true format-sql: true hibernate: ddl-auto: create-droop naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy properties: hibernate: dialect: org.hibernate.dialect.MySQL57InnoDBDialect

Lo mismo se puede hacer con .properties


No necesita usar variables java. Para incluir variables de entorno del sistema, agregue lo siguiente a su archivo application.properties :

spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB" spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME} spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PASSWORD}

Pero la forma sugerida por @Stefan Isele es más preferible, porque en este caso debe declarar solo una variable env: spring.profiles.active . Spring leerá automáticamente el archivo de propiedades apropiado por la plantilla application-{profile-name}.properties .


Tal vez escribo esto demasiado tarde, pero he tenido un problema similar cuando he tratado de anular los métodos para leer las propiedades.

Mi problema ha sido: 1) Leer la propiedad de env si esta propiedad se ha configurado en env 2) Leer la propiedad de la propiedad del sistema si esta propiedad se ha establecido en la propiedad del sistema 3) Y por último, leer de las propiedades de la aplicación.

Entonces, para resolver este problema, voy a mi clase de configuración de bean

@Validated @Configuration @ConfigurationProperties(prefix = ApplicationConfiguration.PREFIX) @PropertySource(value = "${application.properties.path}", factory = PropertySourceFactoryCustom.class) @Data // lombok public class ApplicationConfiguration { static final String PREFIX = "application"; @NotBlank private String keysPath; @NotBlank private String publicKeyName; @NotNull private Long tokenTimeout; private Boolean devMode; public void setKeysPath(String keysPath) { this.keysPath = StringUtils.cleanPath(keysPath); } }

Y sobrescribir fábrica en @PropertySource. Y luego he creado mi propia implementación para leer propiedades.

public class PropertySourceFactoryCustom implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { return name != null ? new PropertySourceCustom(name, resource) : new PropertySourceCustom(resource); } }

Y creó PropertySourceCustom

public class PropertySourceCustom extends ResourcePropertySource { public LifeSourcePropertySource(String name, EncodedResource resource) throws IOException { super(name, resource); } public LifeSourcePropertySource(EncodedResource resource) throws IOException { super(resource); } public LifeSourcePropertySource(String name, Resource resource) throws IOException { super(name, resource); } public LifeSourcePropertySource(Resource resource) throws IOException { super(resource); } public LifeSourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException { super(name, location, classLoader); } public LifeSourcePropertySource(String location, ClassLoader classLoader) throws IOException { super(location, classLoader); } public LifeSourcePropertySource(String name, String location) throws IOException { super(name, location); } public LifeSourcePropertySource(String location) throws IOException { super(location); } @Override public Object getProperty(String name) { if (StringUtils.isNotBlank(System.getenv(name))) return System.getenv(name); if (StringUtils.isNotBlank(System.getProperty(name))) return System.getProperty(name); return super.getProperty(name); } }

Entonces, esto me ha ayudado.


Usando Spring context 5.0, logré cargar correctamente el archivo de propiedades correcto basado en el entorno del sistema a través de la siguiente anotación

@PropertySources({ @PropertySource("classpath:application.properties"), @PropertySource("classpath:application-${MYENV:test}.properties")})

Aquí, el valor MYENV se lee del entorno del sistema y, si el entorno del sistema no está presente, se cargará el archivo de propiedades del entorno de prueba predeterminado; si le doy un valor MYENV incorrecto, no se podrá iniciar la aplicación.

Nota: para cada perfil, desea mantener - necesitará hacer un archivo application- [profile] .property y aunque utilicé Spring context 5.0 y no Spring boot - creo que esto también funcionará en Spring 4.1


Here hay un código de fragmento a través de una cadena de archivos de propiedades de entornos que se están cargando para diferentes entornos.

Archivo de propiedades bajo los recursos de su aplicación ( src / main / resources ): -

1. application.properties 2. application-dev.properties 3. application-uat.properties 4. application-prod.properties

Idealmente, application.properties contiene todas las propiedades comunes que son accesibles para todos los entornos y las propiedades relacionadas con el entorno solo funcionan en entornos específicos. por lo tanto, el orden de carga de estos archivos de propiedades será tal:

application.properties -> application.{spring.profiles.active}.properties.

Fragmento de código aquí: -

import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class PropertiesUtils { public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active"; public static void initProperties() { String activeProfile = System.getProperty(SPRING_PROFILES_ACTIVE); if (activeProfile == null) { activeProfile = "dev"; } PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); Resource[] resources = new ClassPathResource[] {new ClassPathResource("application.properties"), new ClassPathResource("application-" + activeProfile + ".properties")}; propertySourcesPlaceholderConfigurer.setLocations(resources); } }