CA error when create docker image with spring-native - spring-boot

I'm trying to create my first "native java app" using spring-native. I modify my pom adding this
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-native</artifactId>
<version>0.10.5</version>
</dependency>
and this ( in the plugin part )
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
</image>
</configuration>
</plugin>
If I run "mvn clean package" everythng works fine; but when I try "spring-boot:build-image" I get this error (the part of the picture that you can't see says "x509: certificate signed by unknown authority"):
I already tried to add to intellij the certs (image below) of the site but I get the same error.
Any suggestion?

The attempt to download from https://github.com/graalvm/graalvm-ce-builds/releases is happening inside a Docker container that runs the Cloud Native Buildpacks builder and buildpacks. Certificate errors like this can happen when the Docker container is behind a corporate HTTP proxy that uses custom CA certificates. There is a Paketo buildpacks issue and a Spring Boot issue that cover similar errors.
Adding certificates to a JDK trust store will not fix the issue. Certificates must be provided to the builder container when it is launched. This is covered in the Paketo documentation and in the Spring Boot documentation, but it is a little difficult to understand exactly how to configure certificates.
As an example:
First create a bindings directory in the root of your project structure (at the same level as the project src directory) and copy the custom certificate to that directory (where my-custom-certificate.crt is a CA certificate in PEM format):
$ mkdir -p bindings/certificates
$ echo "ca-certificates" > bindings/certificates/type
$ cp /some/path/to/my-custom-certificate.crt bindings/certificates/my-custom-certificate.crt
$ tree bindings
bindings
├── certificates
│   ├── my-custom-certificate.crt
│   └── type
Then configure the Spring Boot Maven plugin to provide the binding to the Paketo CNB builder when the image is built:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<builder>paketobuildpacks/builder:tiny</builder>
<env>
<BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
</env>
<bindings>
<binding>${basedir}/bindings/certificates:/platform/bindings/ca-certificates</binding>
</bindings>
</image>
</configuration>
</plugin>
Note that the bindings configuration of the Spring Boot Maven plugin requires Spring Boot version 2.5.0 or greater.

Related

Cloud Run, Secret Manager and Spring Boot

I want to load whole .properties file from GCP Secret Manager to my Spring Boot application.
Secret is "mounted as volume" in Cloud Run (whole .properties file, in path /secrets/secret.properties), but I cannot manage to load it to Spring Boot using spring.config.import
I was trying:
spring.config.import=optional:configtree:/secrets/
spring.config.import=optional:classpath:/secrets/secret.properties
spring.config.import=optional:/secrets/secret.properties
but nothing works. Values are not visible in Spring Boot application.
(java.lang.IllegalArgumentException: Could not resolve placeholder 'x' in value "${x}")
When putting file on resource classpath, everything works.
Here the set up that I have tested and which works (don't forget to grant the correct permissions)
JIB configuration
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<container>
<args>--spring.config.location=file:///secret/my.properties</args>
</container>
<to>
<image>gcr.io/<PROJECT_ID>/springboot</image>
<credHelper>gcr</credHelper>
</to>
</configuration>
</plugin>
...
My Cloud Run deployment
gcloud beta run deploy --image=gcr.io/<PROJECT_ID>/springboot \
--region=us-central1 --allow-unauthenticated --platform=managed \
--set-secrets=/secret/my.properties=projects/<PROJECT_Number>/secrets/springboot:1 \
secret-springboot

Dockerfile "VOLUME" equivalent when using Spring Boot Paketo Buildpack

I'm currently working on migrating the containerization of Spring Boot App from Dockerfile file to the Spring Boot Maven Plugin build-image.
Now I am wondering how to configure a volume in this scenario. The equivalent to having a VOLUME ["/var/store"] declartion in the Dockerfile. I already Googled for a while, help appreciated. THX!
It depends on the purpose.
If you want to add a volume mount when the buildpacks are running, then you would add a <binding> to your pom.xml.
https://docs.spring.io/spring-boot/docs/2.5.2/maven-plugin/reference/htmlsingle/#build-image.customization
Volume bind mounts that should be mounted to the builder container when building the image. The bindings will be passed unparsed and unvalidated to Docker when creating the builder container.
Bindings must be in one of the following forms:
<host source path>:<container destination path>[:<options>]
<host volume name>:<container destination path>[:<options>]
Ex: results in /host/workspace being mounted into /workspace when the buildpacks execute
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<bindings>
<binding>/host/workspace:/workspace</binding>
</bindings>
</image>
</configuration>
</plugin>
</plugins>
</build>
</project>
This would be the same as using the pack build --volume flag, if one is using the pack cli instead of Spring Boot's Maven plugin.
You can bind volumes when you run your application. That simply uses the standard tools and arguments for your container runtime. For example, you can docker run -v and map in a volume.
If you want the specific behavior of the VOLUME entry in a Dockerfile (which doesn't actually do 1 or 2 above), that's not exposed for images created using Buildpacks, which is what Spring Boot is using. If this is what you want, I would encourage you to read this SO post on volumes and reconsider if you really need it at all.

Spring Boot Cloud Native Buildpacks on Heroku?

I configured my Spring Boot project to use cloud Native Buildpacks to build its docker image as below:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>my-image</name>
</image>
</configuration>
</plugin>
</plugins>
</build>
The resulting Docker image works fine, but I would like to deploy it on Heroku.
I pushed it to the Heroku Container Registry and tried to release it as explained below:
https://devcenter.heroku.com/articles/container-registry-and-runtime#building-and-pushing-image-s
https://devcenter.heroku.com/articles/container-registry-and-runtime#releasing-an-image
When I run:
heroku container:release web --app my-app
I get the following error:
▸ Expected response to be successful, got 404
By googling the error, it seems that it is due to the fact that the resulting Docker image uses
ENTRYPOINT instead of CMD to start the application, as explained in the links below:
https://github.com/grandnode/grandnode/issues/563
https://github.com/heroku/cli/issues/1081
https://devcenter.heroku.com/articles/container-registry-and-runtime#dockerfile-commands-and-runtime
Is it possible to configure the Spring Boot Buildpack in order to use CMD instead of ENTRYPOINT? Or any other solution to deploy the resulting Docker image on Heroku?

Spring Contract Maven Plugin pushStubsToScm does not work

I tried to use Spring Contract Maven Plugin in a producer side to upload the stubs jar and share it with consumers.
I am using Spring Cloud Contract 2.0.0.
I configured the spring-cloud-contract-maven-plugin in my project, the codes is uploaded to Github.
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<basePackageForTests>com.example.demo</basePackageForTests>
<baseClassMappings>
<baseClassMapping>
<contractPackageRegex>.*rest.*</contractPackageRegex>
<baseClassFQN>com.example.demo.RestVerifierBase</baseClassFQN>
</baseClassMapping>
</baseClassMappings>
<!-- We want to pick contracts from a Git repository -->
<!--<contractsRepositoryUrl>git://file://${project.basedir}/target/contract_git/</contractsRepositoryUrl>-->
<!-- Example of URL via git protocol -->
<!--<contractsRepositoryUrl>git://git#github.com:spring-cloud-samples/spring-cloud-contract-samples.git</contractsRepositoryUrl>-->
<!-- Example of URL via http protocol -->
<!--<contractsRepositoryUrl>git://https://github.com/spring-cloud-samples/spring-cloud-contract-samples.git</contractsRepositoryUrl>-->
<contractsRepositoryUrl>git://https://github.com/hantsy/contracts-git.git</contractsRepositoryUrl>
<!-- We reuse the contract dependency section to set up the path
to the folder that contains the contract definitions. In our case the
path will be /groupId/artifactId/version/contracts -->
<contractDependency>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
</contractDependency>
<!-- The mode can't be classpath -->
<contractsMode>REMOTE</contractsMode>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<!-- By default we will not push the stubs back to SCM,
you have to explicitly add it as a goal -->
<goal>pushStubsToScm</goal>
</goals>
</execution>
</executions>
</plugin>
When I ran command mvn clean install -DskipTests -DcontractsRepositoryUsername=hantsy -DcontractsRepositoryPassword=mypassword and got the failure.
Caused by: org.eclipse.jgit.errors.TransportException: https://github.com/hantsy/contracts-git.git: Authentication is required but no CredentialsProvider has been registered
Update: If I set contractsMode to LOCAL, it will fail with downloading stubs jar error, maybe similar with this issue, in the new version 2.0.0, Spring Cloud contracts can not resolve jars from Local maven repos as expected when stubsMode is set to LOCAL.
Update 2: I also tried to add contractsRepositoryUsername and contractsRepositoryPassword in spring contract maven plugin config, it does not work.
contractsMode needs to be REMOTE. I've taken your example and it works well with:
<contractsRepositoryUrl>git://git#github.com:marcingrzejszczak/contracts-git.git</contractsRepositoryUrl>
<contractsMode>REMOTE</contractsMode>
with passing the credentials manually I see sth absolutely bizarre...
I see [INFO] Passed username and password - will set a custom credentials provider which means that username and password got passed and I'm using them. But actually what I get is Authentication is required but no CredentialsProvider has been registered, which makes no sense. Can you file another bug for that? The workaround is to use the agent.
UPDATE:
The issue got fixed here https://github.com/spring-cloud/spring-cloud-contract/issues/678

maven cargo plugin with tomcat6

I'm trying to setup maven cargo plugin. I have the following requirements:
tomcat 6
custom server.xml
custom context.xml
log4j jar deployed to tomcat lib
install tomcat on the machine if it's not there already
tie to maven's install lifecycle phase to deploy a war and restart the container
make the deployed war be ROOT.war
I've followed the following: http://www.java-tutorial.ch/maven/maven-tomcat-deployment-using-cargo. This isn't the complete feature set I want, and even it doesn't work entirely. This is what I get:
Can't load log handler "4host-manager.org.apache.juli.FileHandler"
[INFO] [talledLocalContainer] java.lang.ClassNotFoundException: 4host-manager.org.apache.juli.FileHandler
And then when mvn install returns I do ps -ef and there's no tomcat process.
Also it copies the war to ROOT.war but the old ROOT/ directory is not replaced so the new ROOT.war doesn't actually get deployed.
For the "install tomcat if not already there" requirement, it seems like this should be absolutely straightforward, yet when I provide
<zipUrlInstaller>
<url>http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.32/bin/apache-tomcat-6.0.32.zip</url>
<extractDir>/usr/local</extractDir>
</zipUrlInstaller>
and run mvn cargo:install, it throws this:
org.codehaus.cargo.container.ContainerException: Failed to get container installation home as the container has not yet been installed. Please call install() first.
Which is puzzling. It wants me to call install first, but I AM calling install.
Ideas?
Link you followed has given demo for cargo 1.0.6. Recent version available is 1.1.1 so I suggest you to use recent and there is certain changes in child tags
As described in post http://cargo.codehaus.org/Deploying+to+a+running+container. There are ceratin changes in child tags of ZipUrlInstaller.
<!--
Careful: As described in the ZipUrlInstaller documentation,
Cargo versions older than 1.1.0 accept only installDir, you therefore
need to set installDir instead of downloadDir and extractDir.
-->
Try to use maven archetype to create cargo sample project following post http://cargo.codehaus.org/Maven2+Archetypes. I suggest you to user "Single Webapp Module Archetype"
After setting up maven project, You can install tomcat 6 running mvn cargo:install -P tomcat6x command.
pom.xml snippet of "single webapp module archetype" which can be useful for you.
<profiles>
<profile>
<id>tomcat6x</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<wait>true</wait>
<container>
<containerId>tomcat6x</containerId>
<!-- download zip url -->
<zipUrlInstaller>
<url>http://archive.apache.org/dist/tomcat/tomcat-6/v6.0.32/bin/apache-tomcat-6.0.32.zip</url>
<downloadDir>${project.build.directory}/downloads</downloadDir>
<extractDir>${project.build.directory}/extracts</extractDir>
</zipUrlInstaller>
</container>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
where wait parameter true will give you option to check whether server is running or not.

Resources