Skip to content

Commit be983e1

Browse files
committed
#33: Add building native images with Docker also - incl. Release to Heroku and Docker Hub
1 parent 7a3c6d1 commit be983e1

File tree

2 files changed

+128
-5
lines changed

2 files changed

+128
-5
lines changed

.github/workflows/native-image-compile.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,21 @@ jobs:
4949
steps:
5050
- uses: actions/checkout@v2
5151

52-
- run: echo 'Iam here'
52+
- name: Build Native Image with Docker and Release to Heroku & Docker Hub
53+
run: |
54+
echo ' Login into Heroku Container Registry first, so that we can push our Image later'
55+
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin registry.heroku.com
56+
57+
echo 'Compile Native Image using Docker'
58+
docker build . --tag=registry.heroku.com/spring-boot-graal/web
59+
60+
echo 'Push to Heroku Container Registry'
61+
docker push registry.heroku.com/spring-boot-graal/web
62+
63+
echo 'Release Dockerized Native Spring Boot App on Heroku'
64+
./heroku-release.sh spring-boot-graal
65+
66+
echo 'Push to Docker Hub also, since automatic Builds there don't have anough RAM to do a docker build'
67+
echo "$DOCKER_HUB_TOKEN" | docker login -u "$DOCKER_HUB_USERNAME" --password-stdin
68+
docker tag registry.heroku.com/spring-boot-graal/web jonashackt/spring-boot-graalvm:latest
69+
docker push jonashackt/spring-boot-graalvm:latest

README.md

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ This project is used as example in some articles:
4747
* [Build and Run your Native Image compilation on a Cloud-CI provider like TravisCI](#build-and-run-your-native-image-compilation-on-a-cloud-ci-provider-like-travisci)
4848
* [Prevent the 'java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]' error](#prevent-the-javalangunsatisfiedlinkerror-no-netty_transport_native_epoll_x86_64-in-javalibrarypath-usrjavapackageslib-usrlib64-lib64-lib-usrlib-error)
4949
* [Tackling the 'There was an error linking the native image /usr/bin/ld: final link failed: Memory exhausted' error](#tackling-the-there-was-an-error-linking-the-native-image-usrbinld-final-link-failed-memory-exhausted-error)
50+
* [Build and Run your Native Image compilation on GitHub Actions](#build-and-run-your-native-image-compilation-on-github-actions)
5051
* [Use Docker to compile a Spring Boot App with GraalVM](#use-docker-to-compile-a-spring-boot-app-with-graalvm)
5152
* [Tackling 'Exception java.lang.OutOfMemoryError in thread "native-image pid watcher"' error](#tackling-exception-javalangoutofmemoryerror-in-thread-native-image-pid-watcher-error)
5253
* [Run Spring Boot Native Apps in Docker](#run-spring-boot-native-apps-in-docker)
@@ -944,6 +945,61 @@ user 17m46.032s
944945
sys 0m11.720s
945946
```
946947

948+
# Build and Run your Native Image compilation on GitHub Actions
949+
950+
Since Travis laid down their OpenSource support to a massive degree, many maintainers move their repos over to GitHub Actions - see also this post: https://blog.codecentric.de/en/2021/02/github-actions-pipeline/
951+
952+
So let's implement a [.github/workflows/native-image-compile.yml](.github/workflows/native-image-compile.yml):
953+
954+
```yaml
955+
name: native-image-compile
956+
957+
on: [push]
958+
959+
jobs:
960+
native-image-compile-on-host:
961+
runs-on: ubuntu-latest
962+
963+
steps:
964+
- uses: actions/checkout@v2
965+
966+
- name: Cache SDKMAN archives & candidates
967+
uses: actions/cache@v2
968+
with:
969+
path: ~/.sdkman
970+
key: ${{ runner.os }}-sdkman-${{ hashFiles('pom.xml') }}
971+
restore-keys: |
972+
${{ runner.os }}-sdkman-
973+
974+
- name: Install GraalVM, Maven, Native Image & Run Maven build
975+
run: |
976+
echo 'Install GraalVM with SDKMAN'
977+
curl -s "https://get.sdkman.io" | bash
978+
source "$HOME/.sdkman/bin/sdkman-init.sh"
979+
sdk install java 20.2.0.r11-grl
980+
981+
echo 'Check if GraalVM was installed successfully'
982+
java -version
983+
984+
echo 'Install GraalVM Native Image'
985+
gu install native-image
986+
987+
echo 'Check if Native Image was installed properly'
988+
native-image --version
989+
990+
echo 'Install Maven, that uses GraalVM for later builds'
991+
source "$HOME/.sdkman/bin/sdkman-init.sh"
992+
sdk install maven
993+
994+
echo 'Show Maven using GraalVM JDK'
995+
mvn --version
996+
997+
echo 'Run GraalVM Native Image compilation of Spring Boot App (Maven version instead of ./compile.sh)'
998+
mvn -B clean package -P native --no-transfer-progress
999+
```
1000+
1001+
This one does exactly what we did with TravisCI - building the native image using Maven and installing GraalVM beforehand.
1002+
9471003

9481004
# Use Docker to compile a Spring Boot App with GraalVM
9491005

@@ -1322,6 +1378,20 @@ sys 2m3.179s
13221378
The one thing to take into account is that Native Image compilation will be a bit slower now. So if you run on your local machine with lot's of memory, feel free to delete the ` -J-Xmx4G` parameter :)
13231379

13241380

1381+
### Work around the Heroku 512MB RAM cap: Building our Dockerimage with GitHub Actions
1382+
1383+
```yaml
1384+
native-image-compile-in-docker:
1385+
runs-on: ubuntu-latest
1386+
1387+
steps:
1388+
- uses: actions/checkout@v2
1389+
1390+
- name: Compile Native Image using Docker
1391+
run: docker build . --tag=registry.heroku.com/spring-boot-graal/web
1392+
```
1393+
1394+
13251395
### Pushing and Releasing our Dockerized Native Spring Boot App on Heroku Container Infrastructure
13261396

13271397
Now we should be able to finally [push the build Docker image into Heroku's Container Registry](https://devcenter.heroku.com/articles/container-registry-and-runtime#using-a-ci-cd-platform), from where we're able to run our Spring Boot Native app later on.
@@ -1449,9 +1519,45 @@ $ heroku logs -a spring-boot-graal
14491519
```
14501520
14511521
1522+
### Pushing and Releasing our Dockerized Native Spring Boot App on Heroku Container Infrastructure using GitHub Actions
1523+
1524+
We should also use GitHub Actions to [push the build Docker image into Heroku's Container Registry](https://devcenter.heroku.com/articles/container-registry-and-runtime#using-a-ci-cd-platform).
1525+
1526+
Therefore we need to configure encrypted variables in our GitHub repository in order to push to Heroku's Container Registry:
1527+
`DOCKER_USERNAME` and `DOCKER_PASSWORD`. The first is your Heroku eMail, the latter is your Heroku API key. Be sure to prevent displaying the values in the build log:
1528+
1529+
With the following configuration inside our [.github/workflows/native-image-compile.yml](.github/workflows/native-image-compile.yml), we should be able to successfully log in to Heroku Container Registry:
1530+
1531+
```yaml
1532+
run: |
1533+
echo ' Login into Heroku Container Registry first, so that we can push our Image later'
1534+
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin registry.heroku.com
1535+
```
1536+
1537+
Now after a successful Docker build, that compiles our Spring Boot App into a native executable, we finally need to push the resulting Docker image into Heroku Container Registry.
1538+
1539+
Therefore we need to use the correct tag for our Docker image build([see the docs](https://devcenter.heroku.com/articles/container-registry-and-runtime#pushing-an-existing-image):
1540+
1541+
```shell script
1542+
docker build . --tag=registry.heroku.com/<app>/<process-type>
1543+
docker push registry.heroku.com/<app>/<process-type>
1544+
```
1545+
1546+
This means we add the following `docker tag` and `docker push` command into our [.github/workflows/native-image-compile.yml](.github/workflows/native-image-compile.yml):
1547+
1548+
```yaml
1549+
echo 'Compile Native Image using Docker'
1550+
docker build . --tag=registry.heroku.com/spring-boot-graal/web
1551+
1552+
echo 'Push to Heroku Container Registry'
1553+
docker push registry.heroku.com/spring-boot-graal/web
1554+
```
1555+
1556+
See the paragraph on how to release to Heroku using Containers at [Pushing and Releasing our Dockerized Native Spring Boot App on Heroku Container Infrastructure](#pushing-and-releasing-our-dockerized-native-spring-boot-app-on-heroku-container-infrastructure).)
1557+
14521558

14531559

1454-
# Autorelease on Docker Hub with TravisCI
1560+
# Autorelease on Docker Hub with TravisCI & GitHub Actions
14551561

14561562
We could try to __autorelease to Docker Hub on hub.docker.com:__
14571563

@@ -1475,13 +1581,13 @@ __BUT:__ As the automatic builds feature rely on the Docker Hub build infrastruc
14751581
Error: Image build request failed with exit status 1
14761582
```
14771583

1478-
Since our TravisCI build is now enabled to successfully run our GraalVM Native Image compilation in a Docker build, we could live without the automatic builds feature of Docker Hub - and simply push our Travis' build image to Docker Hub also!
1584+
Since our TravisCI & GitHub Actions builds are now enabled to successfully run our GraalVM Native Image compilation in a Docker build, we could live without the automatic builds feature of Docker Hub - and simply push our build image to Docker Hub also!
14791585

14801586
Therefore you need to create an Access Token in your Docker Hub account at https://hub.docker.com/settings/security
14811587

1482-
Then head over to your TravisCI project settings and add the environment variables `DOCKER_HUB_TOKEN` and `DOCKER_HUB_USERNAME` as already happended for Heroku Container Registry.
1588+
Then head over to your TravisCI & GitHub Actions project settings and add the environment variables `DOCKER_HUB_TOKEN` and `DOCKER_HUB_USERNAME` as already happended for Heroku Container Registry.
14831589

1484-
The final step then is to add the correct `docker login` and `docker push` commands to our [.travis.yml](.travis.yml):
1590+
The final step then is to add the correct `docker login` and `docker push` commands to our [.travis.yml](.travis.yml) and [.github/workflows/native-image-compile.yml](.github/workflows/native-image-compile.yml):
14851591

14861592
```yaml
14871593
# Push to Docker Hub also, since automatic Builds there don't have anough RAM to do a docker build

0 commit comments

Comments
 (0)