<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Miles Bardon</title>
    <description>The latest articles on Forem by Miles Bardon (@tohaker).</description>
    <link>https://forem.com/tohaker</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F231496%2F4e0b6a51-d646-4306-92f1-e00f9c72faa3.jpeg</url>
      <title>Forem: Miles Bardon</title>
      <link>https://forem.com/tohaker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tohaker"/>
    <language>en</language>
    <item>
      <title>Google Cloud Run and Functions with Terraform</title>
      <dc:creator>Miles Bardon</dc:creator>
      <pubDate>Sat, 02 Nov 2019 19:13:25 +0000</pubDate>
      <link>https://forem.com/tohaker/google-cloud-run-and-functions-with-terraform-4bmg</link>
      <guid>https://forem.com/tohaker/google-cloud-run-and-functions-with-terraform-4bmg</guid>
      <description>&lt;h1&gt;
  
  
  What is Google Cloud Run?
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/run/"&gt;Google Cloud Run&lt;/a&gt;, much like &lt;a href="https://cloud.google.com/functions"&gt;Google Cloud Functions&lt;/a&gt;, is a serverless solution for running code only when you need it, and being charged likewise. However, it has one key difference that makes it very flexible for developers: &lt;strong&gt;Containers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Cloud run allows you to build your Docker container, test it locally to your hearts content and push it to a private container repository in Google Cloud Storage. Once the Cloud Run service is created, you will be able to make HTTPS requests which invoke your container, running whatever you've deployed into it.&lt;/p&gt;

&lt;p&gt;I chose this service as I needed to implement a Web Scraper for the &lt;a href="https://www.facebook.com/yugiohbot3000"&gt;YuGiOh Bot 3000&lt;/a&gt;. I had tried AWS Lambda and Google Functions, but neither had the ability to use Chrome and Chromedriver properly. Running this scraper in a Docker container, however, allowed me to test everything worked locally, and be confident that it would work anywhere else. It wouldn't cost the world either, as Cloud Run allows 180,000 vCPU-seconds and 360,000 GB-seconds for free (at the time of writing, this may have changed when you read this. Hello future person! See &lt;a href="https://cloud.google.com/run/pricing"&gt;here&lt;/a&gt; for the up-to-date values).&lt;/p&gt;

&lt;h1&gt;
  
  
  The (TF) Plan
&lt;/h1&gt;

&lt;p&gt;Whenever I deploy a cloud service, I want to be assured that everything can be automated. I've used Terraform a lot in the past, so decided to give it a go in deploying both my Cloud Function (which generates some text) and the Cloud Run service. As it's still in Beta, some of the work I've done may become outdated once Cloud Run and its associated Terraform provider reach standard availability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing the Docker container
&lt;/h2&gt;

&lt;p&gt;The first step to deploying a Cloud Run service is to build, tag and push your Docker container. This can be achieved on the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t gcr.io/${PROJECT}/${SERVICE_NAME} .
docker push gcr.io/${PROJECT}/${SERVICE_NAME}
export DIGEST=$(docker image ls --digests gcr.io/${PROJECT}/${SERVICE_NAME} --format "{{.Digest}}")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We'll use the DIGEST later to ensure new containers are deployed.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; If you are performing these commands in a CI/CD pipeline (such as Travis-CI) you'll need to authenticate Docker to allow it to push to your repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud auth configure-docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up Terraform
&lt;/h2&gt;

&lt;p&gt;To use Cloud Run in Terraform, you need to use the &lt;code&gt;google-beta&lt;/code&gt; provider, as well as the standard &lt;code&gt;google&lt;/code&gt; provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider "google" {
  project = "project_name"
  region  = "us-east1"
  zone    = "us-east1-a"
}

provider "google-beta" {
  project = "project_name"
  region  = "us-east1"
  zone    = "us-east1-a"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It's also a good idea to store the Image repo and digest in variables for Terraform to use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "image" {
  description = "Name of the docker image to deploy."
  default     = "gcr.io/project_name/service_name"
}

variable "digest" {
  description = "The docker image digest to deploy."
  default     = "latest"
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When running Terraform from the command line, set the digest to the one you exported earlier. We will then concatenate the image and the digest, as the provider doesn't actually check if the image has changed. This may be fixed in a future update but for now this will do.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "Planning Terraform."
terraform plan \
    -var="digest=$DIGEST" \
    -out=output.tfplan
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the Cloud Run Service
&lt;/h2&gt;

&lt;p&gt;At the very minimum, you need to provide the name, location, metadata and image location for the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "google_cloud_run_service" "service" {
  name     = var.name
  location = var.location
  provider = "google-beta"

  metadata {
    namespace = var.project
  }

  spec {
    containers {
      image = "${var.image}@${var.digest}"
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I found it useful to also set the memory limit, as my container uses Chromium and needs a fair bit of RAM to run effectively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
spec {
    containers {
      image = "${var.image}@${var.digest}"
      resources {
        limits = {
          cpu    = "1000m"
          memory = "1024Mi"
        }
      }
    }
  }
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And thats it; Your Cloud Run service is deployed!&lt;/p&gt;

&lt;h1&gt;
  
  
  Invoking the Cloud Run Service securely
&lt;/h1&gt;

&lt;p&gt;Security is very important in Cloud computing. You don't want everyone and their dog calling your private function, costing you money and possibly having undesired effects. By default, Cloud Run Services are private and can only be invoked by authorised users.&lt;/p&gt;

&lt;p&gt;If you want to invoke this manually, you'll need to create an IAM user and give them the &lt;code&gt;Cloud Run Invoker&lt;/code&gt; Role. However, if you want to have this invoked by another Cloud Function (as I did), you'll already have a default service account created, usually with the name &lt;code&gt;[ACCOUNT_NUMBER]-compute@developer.gserviceaccount.com&lt;/code&gt;. Giving this the same role will allow any of your Cloud Functions to authorise itself to call your HTTPS service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorising a Python App
&lt;/h2&gt;

&lt;p&gt;I used python for my Cloud Functions, so here is the code needed to authorise it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests

receiving_service_url = 'https://some-app-name.run.app'

# Set up metadata server request
# See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
metadata_server_token_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='

token_request_url = metadata_server_token_url + receiving_service_url
token_request_headers = {'Metadata-Flavor': 'Google'}

# Fetch the token
token_response = requests.get(token_request_url, headers=token_request_headers)
jwt = token_response.content.decode("utf-8")

# Provide the token in the request to the receiving service
receiving_service_headers = {'Authorization': f'bearer {jwt}'}
service_response = requests.get(receiving_service_url, headers=receiving_service_headers)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The final line is a standard &lt;code&gt;requests&lt;/code&gt; GET request, which you can add &lt;code&gt;params&lt;/code&gt; to if you so desire. More information about service-to-service requests can be found &lt;a href="https://cloud.google.com/run/docs/authenticating/service-to-service"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This has been a whistlestop tour of deploying Cloud Run through automation. There wasn't much out there about this at the time of publication, so I decided to share my newfound knowledge. Please comment below if these steps don't work for you - there may be updates to the service as it evolves. Thanks for reading!&lt;/p&gt;

</description>
      <category>google</category>
      <category>terraform</category>
      <category>functions</category>
      <category>python</category>
    </item>
    <item>
      <title>Stack to the Future - How I migrated an automated build from Maven to Gradle.</title>
      <dc:creator>Miles Bardon</dc:creator>
      <pubDate>Fri, 20 Sep 2019 22:37:38 +0000</pubDate>
      <link>https://forem.com/tohaker/stack-to-the-future-how-i-migrated-an-automated-build-from-maven-to-gradle-2b6m</link>
      <guid>https://forem.com/tohaker/stack-to-the-future-how-i-migrated-an-automated-build-from-maven-to-gradle-2b6m</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;When I was introduced to the &lt;a href="https://github.com/schwabdidier/GazePlay"&gt;GazePlay&lt;/a&gt; project, I jumped at the chance to try to fix some of the issues on it, and just get to grips with contributing to an Open Source project that was really doing some good.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One problem; I couldn't build it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project had a Maven build system, and everything hinged on it. From build and test, through to releases, everything was written in huge XML files, which (in my humble opinion) makes it difficult to read and understand. There was a huge dependency on the developer working on the project having the JavaFX libraries on their global class-path. Not only this, but the project was built on Java 8, with an out-of-date version of JavaFX (i.e. the one included in older patches of Oracle Java 8).&lt;/p&gt;

&lt;p&gt;This was not a sustainable development environment, so I took it upon myself that my first contribution would be to leverage the power of Gradle to simplify the build, and the new features and support of OpenJDK 11 and OpenJFX 11. The intention was to allow any developer to clone the project and run it with little-to-no setup. &lt;strong&gt;This article is a guide to how I acheived this, and is in no way a definitive guide to migration.&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Build, Test and Dependencies
&lt;/h1&gt;

&lt;p&gt;The first step in this task was to get gradle to do most of the hard work. By running the command &lt;code&gt;gradle init&lt;/code&gt; in a directory with a Maven project, you can get Gradle to create the wrapper scripts, properties files and a &lt;code&gt;build.gradle&lt;/code&gt; file for the equivalent &lt;code&gt;pom.xml&lt;/code&gt; file in the root and inner projects.&lt;/p&gt;

&lt;p&gt;Here is my new root &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
 * This file was generated by the Gradle 'init' task.
 */

allprojects {
    group = 'com.github.schwabdidier'
    version = '1.6.2-SNAPSHOT'
}

subprojects {
    apply plugin: 'java'
    apply plugin: 'maven-publish'

    repositories {
        mavenLocal()
        maven {
            url = 'http://jcenter.bintray.com'
        }

        maven {
            url = 'https://jitpack.io'
        }

        maven {
            url = 'http://repo.maven.apache.org/maven2'
        }

        maven {
            url = 'https://raw.github.com/agomezmoron/screen-recorder/mvn-repo'
        }
    }

    dependencies {
        compileOnly 'com.google.code.findbugs:findbugs:3.0.1'
    }

    sourceCompatibility = '1.8'

    publishing {
        publications {
            maven(MavenPublication) {
                from(components.java)
            }
        }
    }

    tasks.withType(JavaCompile) {
        options.encoding = 'UTF-8'
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And here is one of the subproject &lt;code&gt;build.gradle&lt;/code&gt; files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
 * This file was generated by the Gradle 'init' task.
 */

dependencies {
    compile 'com.github.agomezmoron:screen-recorder:0.0.3'
    compile project(':gazeplay-commons')
    compile project(':gazeplay-data')
    ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What this doesn't do, however, is migrate the Maven Plugins. In particular, to get the build working, I had to add in the javafx and lombok annotation processing plugins to the root &lt;code&gt;build.gradle&lt;/code&gt;. License reporting was also required, so I included this too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.8'
    id 'io.freefair.lombok' version '4.0.1'
    id 'com.github.hierynomus.license-report' version '0.15.0'
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The final steps to get a build working was to add the plugins to each subproject recursively, and configure them as needed.&lt;/p&gt;

&lt;p&gt;Handily, the Gradle initialisation had already provided me with the &lt;code&gt;subproject&lt;/code&gt; block and I just had to add this configuration to it;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;subprojects {
    apply plugin: 'java'
    apply plugin: 'maven-publish'
    apply plugin: 'org.openjfx.javafxplugin'
    apply plugin: 'io.freefair.lombok'
    apply plugin: 'com.github.hierynomus.license-report'

    javafx {
        version = "11.0.2"
        modules = [ 'javafx.controls', 'javafx.swing', 'javafx.media', 'javafx.web' ]
    }
   ...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; At this stage I had set my &lt;code&gt;JAVA_HOME&lt;/code&gt; to point to my local installation of AdoptOpenJDK 11. As this requires a modular version of OpenJFX, I had to go through all the project imports and determine which modules to include. This wasn't mimicked in the Maven POM as that just needed to import JavaFX Controls.&lt;/p&gt;

&lt;p&gt;A few library upgrades, swapping out deprecated APIs and some documentation later, the build was succeeding and I could open my PR! &lt;em&gt;&lt;strong&gt;Huzzah!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I could test the Gradle configuration worked by running &lt;code&gt;gradlew run&lt;/code&gt; to run the application from the commandline. The games worked as expected, and I could move onto the next stage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/KEYEpIngcmXlHetDqz/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/KEYEpIngcmXlHetDqz/giphy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Release the &lt;del&gt;hounds&lt;/del&gt; Jars
&lt;/h1&gt;

&lt;p&gt;One of the key goals of this task was to be able to bundle releases to users of the application, in the form of a launchable &lt;code&gt;.jar&lt;/code&gt; file. Fortunately, Gradle recognised all my dependencies and added their Jars to the &lt;code&gt;lib&lt;/code&gt; folder when I ran the &lt;code&gt;distZip&lt;/code&gt; task from the &lt;a href="https://docs.gradle.org/current/userguide/distribution_plugin.html"&gt;&lt;code&gt;distribution&lt;/code&gt; plugin&lt;/a&gt;. What the launch jar &lt;em&gt;couldn't do&lt;/em&gt; was FIND any of the dependencies!&lt;/p&gt;

&lt;p&gt;To fix this, I had to adjust the jar manifest configuration to add both the Main-Class to launch, and the Class-Path for all the runtime dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jar {
    manifest {
        attributes (
            "Main-Class": 'net.gazeplay.GazePlayLauncher',
            "Class-Path": configurations.runtime.collect { it.getName() }.join(' ')
        )
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By &lt;code&gt;collect&lt;/code&gt;ing all the &lt;code&gt;runtime&lt;/code&gt; &lt;code&gt;configurations&lt;/code&gt;, and &lt;code&gt;it&lt;/code&gt;erating through them all, I could &lt;code&gt;getName&lt;/code&gt; and &lt;code&gt;join&lt;/code&gt; them together with a space.&lt;/p&gt;

&lt;p&gt;Now, launching the created &lt;code&gt;gazeplay-project-1.6.2-SNAPSHOT.jar&lt;/code&gt; would actually load the other Jars into the classpath and allow the games to run!&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Packaging Task
&lt;/h2&gt;

&lt;p&gt;Since packaging the app for release required a few steps, I decided to create my own custom task in a new &lt;code&gt;.gradle&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.apache.tools.ant.filters.ReplaceTokens

task packageApp(dependsOn: ['assembleDist', 'downloadLicenses', 'scriptsForRelease']) {
    tasks.findByName('assembleDist').mustRunAfter('downloadLicenses')
    tasks.findByName('assembleDist').mustRunAfter('scriptsForRelease')
}

task scriptsForRelease(type: Copy) {
    from "${rootDir}/gazeplay-dist/src/main/bin"
    into "${rootDir}/build/scripts"
    filter(
        ReplaceTokens, tokens: [VERSION: project.version, NAME: project.name]
    )

    outputs.upToDateWhen { false } // Forces the task to rerun every time, without requiring a clean.
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;packageApp&lt;/code&gt; task downloads all the licenses for the dependencies, carries out the &lt;code&gt;scriptsForRelease&lt;/code&gt; task to substitute environment variables for the project version and name, and then packages these all up into a Zip and Tar archive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gradle Release Plugin
&lt;/h2&gt;

&lt;p&gt;By default, Gradle does not included a direct equivalent to the &lt;code&gt;maven-release-plugin&lt;/code&gt; that the project had been using up to this point. The release plugin is designed to ensure all files are commited and pushed to master, and then tags the commit with the version number in the project. Finally, it increments this version and commits everything again, ready for further development.&lt;/p&gt;

&lt;p&gt;For this project, I went for the most popular Gradle iteration of the plugin; the &lt;a href="https://github.com/researchgate/gradle-release"&gt;Researchgate Release&lt;/a&gt; plugin. All that was needed to setup the plugin was specify that the &lt;code&gt;packageApp&lt;/code&gt; task was executed before the release ran; &lt;code&gt;beforeReleaseBuild.dependsOn packageApp&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating a custom JRE
&lt;/h1&gt;

&lt;p&gt;The main feature of JDK 9 was the introduction of the modular JDK and JRE. This is of course prevalent in Open JDK 11, and is key to creating a custom JRE for distribution along with the app. To do this, I opted to use the &lt;a href="https://badass-runtime-plugin.beryx.org/releases/latest/"&gt;Badass Runtime Plugin&lt;/a&gt;, which wraps the &lt;code&gt;jlink&lt;/code&gt; command with a Gradle Task. By defining the exact modules the application requires to run, it's possible to generate a JRE as a build task, with the included &lt;code&gt;jre&lt;/code&gt; task.&lt;/p&gt;

&lt;p&gt;Here is a snippet of the modules included in the JRE created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ext.jreModules=['java.base',\
  'java.compiler',\
  'java.datatransfer',\
  'java.desktop',\
  'java.instrument',\
  'java.logging',\
  'java.management',\
  'java.management.rmi',\
  'java.naming',\
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All that is left to do is configure the runtime plugin as so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;runtime {
    options = ['--compress', '2', '--no-header-files', '--no-man-pages']
    modules = jreModules
    jreDir = file("gazeplay-dist/src/jre")
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;jlink&lt;/code&gt; command options are specified to keep the folder as small as possible, and the directory is set to match where the JRE 1.8 was located, for consistency with the existing project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;It may not have been the most glamourous project, but I learnt a whole lot about Gradle, custom tasks and third-party plugins. Additionally, I'm no expert on custom JREs, or the modularity of Java 9+, but this project gave me the step up needed to start investigating and learning more about it. In the end, I hope this article helps someone solve that little annoying problem they have, or is just an interesting read for someone going through the same process.&lt;/p&gt;

&lt;p&gt;For more details on everything I've discussed here, feel free to &lt;a href="https://github.com/schwabdidier/GazePlay/pull/880"&gt;check out the PR&lt;/a&gt; with all the code.&lt;/p&gt;

</description>
      <category>java</category>
      <category>gradle</category>
      <category>maven</category>
    </item>
  </channel>
</rss>
