CI with GCP Cloud Build – evaluation

Cloud Build on of the services available on Google Cloud Platform. Evaluation happened January 2021 and I believe that is still improving. This post is supposed to be part of the bigger series with a unified structure.

Overview:

  • Even though Cloud Build labels itself as CI/CD tool it lacks the CD features (e.g. deployment strategies, manual approval stages etc.) – nobody prevents you from developing those
  • Run in GCP or has some support for local execution as well
  • Build using wiring Docker containers together. Executed on single VM, you can upscale VM to high cpu machines up to 32cpu. 

Continous Integration features:

Pricing:

Summary:

Purely CI system with capability to build (~ Cloud Build). No triggers for time based related things. So either Event based (commit, tag, …) or manual trigger. Probably could be emulated via Cloud Function to trigger to simulate Time Based Trigger. Has ability to run locally which is nice. Scales up to 32cpu machines. Prices based on build time (clock time). Doesn’t offer Approval stages, security model based on IAM and seems that you cannot grant permission on particular configuration/build. Doesn’t have concept of pipeline – but rather set of tasks steps(stages). Definition lives in Git – so LTS branches should be buildable. To have full end-2-end deployment, you need a CD system. This system manages just “build artefact”. 

Build Number

One of the most important thing during the SDLC (for sure apart from the other stuff) is to keep control over deployed artifacts to all environments at any given time. Lack of control leads to chaos and generates a lot of extra work to the team, degrades throughput, morale and motivation. No need to even mention that arguments among team members regarding deployed features or fixes definitely do not contribute well to the team spirit.
One of the common approaches mitigating this risk is generating a build number to every single build fully automatically. Let’s take a look at how to accomplish this in common project set up – maven project build on build server e.g. TeamCIty. Sample web application follows.
Common place where to store such kind of info is MANIFEST.MF file. All kind of archives have this file located in /META-INF/MANIFEST.MF. Various technologies like OSGi use this location for various metadata. Taking advantage of maven-war-plugin the content of MANIFEST.MF can be easily customized as follows (${xx} are maven variables):
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: ${user.name}
Build-Jdk: ${java.version}
Specification-Title: ${project.name}
Specification-Version: ${project.version}
Specification-Vendor: ${project.organization.name}
Implementation-Title: ${project.name}
Implementation-Version: ${project.version}
Implementation-Vendor-Id: ${project.groupId}
Implementation-Vendor: ${project.organization.name}

To set up a maven project pom file is pretty easy:


org.apache.maven.plugins
maven-war-plugin

true
true

${build.number}

Where build.number variable gets supplied by build server in arbitrary format, e.g. for TeamCity build server:

Build number is visible in build queue status page as well:
To access these project build specific information simple jsp page can be created:
The controller accessing these information using Spring MVC (simplified example) can look like:
@Controller
public class ProjectInfoController {

    @RequestMapping("/info")
    public ModelAndView getProjectInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {

        ModelAndView modelAndView = new ModelAndView("projectInfoView");

        ServletContext servletContext = request.getSession().getServletContext();

        Properties properties = new Properties();
        InputStream is = servletContext.getResourceAsStream("/META-INF/MANIFEST.MF");

        properties.load(is);

        modelAndView.addObject("buildBy",properties.getProperty("Built-By"));
        modelAndView.addObject("buildJdk",properties.getProperty("Build-Jdk"));
        modelAndView.addObject("specificationVersion",properties.getProperty("Specification-Version"));
        modelAndView.addObject("specificationTitle",properties.getProperty("Specification-Title"));
        modelAndView.addObject("implementationVendor",properties.getProperty("Implementation-Vendor-Id"));
        modelAndView.addObject("buildNumber",properties.getProperty("Build-Number"));

        return modelAndView;
    }
}

Accessing MANIFEST.MF in JAR file has a different approach. Motivation taken from Spring source code:

Package  package = someClass.getPackage( );
String version = package.getImplementationVersion();

JSP page or other presentation layer shouldn’t be a problem for anyone.