For developers programming in long-established languages like Java, JavaScript or Python, the best way to build continuous integration and continuous delivery (CI/CD) workflows with Artifactory is pretty familiar. A mature set of dependency management systems for those languages and container solutions like Docker provide a clear roadmap.

But if you’re programming your applications in GoLang, how hard is it to practice CI/CD with the same kind of efficiency?

As it turns out, it’s gotten a lot easier, especially with some of the latest innovations in Go. With Artifactory’s native support for GoLang, the path to quality CI/CD is much clearer.

At JFrog, we’re big fans of GoLang, using it as the language for several of our flagship solutions. And we practice what we promote, too, using Artifactory at the heart of our CI/CD. Here are some of the practices we can recommend:

1. Use Go Modules

Unlike many established programming languages, initial releases of GoLang didn’t provide a common mechanism for managing versioned dependencies. Instead, the Go team encouraged others to develop add-on tools for Go package versioning.

That changed with the release of Go 1.11 in August, 2018, with support for Go modules. Now the native dependency management solution for GoLang, Go modules are collections of related Go packages that are versioned together as a single unit. This enables developers to share code without repeatedly downloading it. 

go.mod

If you haven’t adopted Go modules yet, then you’ll need to follow the steps below:

go mod initgo.modgo mod tidy.proto
go.mod

Note that the version numbers must conform to semver convention (for example, v1.2.1 instead of 20190812, or 1.2.1) as required by the go command. You should avoid using pseudo versions like the one shown above (v0.0.0-yyyymmddhhmmss-abcdefabcdef) — although commit hash pseudo-version were introduced to bring Go Modules support to untagged projects, they should be only used as a fallback mechanism. If the dependencies you need have release tags, use those tags in your require statements.

In your own code, you can import this Go module along with other dependencies:

Then you can reference the module functions in your GoLang code:

2. Use GOPROXY to Ensure Immutability and Availability

Once you maintain your GoLang dependencies as versioned modules, you can keep them as immutable entities by setting up a GOPROXY. In this way, you can always guarantee what a specific version of a module contains, so your builds are always repeatable.

Will you be using Go modules that are publicly available open-source packages? Ones you create and share with the OSS community? Modules you keep private to just your team? Here are ways to do each, or all at once, and ensure that those unchanging versioned modules are always available for your builds.

GOLANG.ORG

proxy.golang.orgindex.golang.orgsum.golang.org

The go.dev site is also maintained by the Go team and is the hub for Go users providing centralized and curated resources from across the Go ecosystem. Within this site, you can explore pkg.go.dev to search among thousands of open-source Go packages through a friendly UI.

Artifactory Go Registries

While it’s good to share, you’ll likely also need to restrict the use of some Go modules you create to within your organization. With Artifactory, you can set up both local and remote Go Registries, making public and private modules equally available to your builds.

You can proxy the Go mirror service as a remote Go registry in Artifactory, providing your build system with a local cache that further speeds up your builds and helps protect against network connection outages. Setting one up is easy.

Artifactory Go Registry

You can also configure one or more local Go registries for modules you need to maintain privately within your organization.

When you combine local and remote registries into a Virtual Repository, your builds can resolve Go module dependencies from both a public source and the modules you create and maintain privately.

You can learn more about how to configure your GOPROXY for Artifactory repositories through this blog post on Choosing Your GOPROXY for Go Modules.

3. Use Artifactory Repository Layouts

go build

For these intermediate Go artifacts, you’ll use Artifactory’s generic repositories. Structuring those repositories in a smart way can help you control the flow of your binaries through development, test, and production with separate repositories for each of those stages. To help you do this, use the Custom Repository Layout feature of Artifactory with those generic repositories.

Create a custom layout that is similar to the following:

[org]/[name<.+>]/[module]-[arch<.+>]-[baseRev].[ext]

When you configure the custom layout, you should test the artifact path resolution to confirm how Artifactory will build module information from the path using the layout definitions.

4. Build Once and Promote

With your repositories properly set up for your Go builds, you can start to move them through your pipeline stages efficiently. 

Many software development procedures require a fresh complete or partial build at each staging transition of development, testing, and production. But as developers continue to change shared code, each new build introduces new uncertainties; you can’t be certain what’s in it. Even with safeguards to help assure deterministic builds, that may still require repeating the same quality checks in each stage.  

Instead, build your Go-based microservices once, then promote them to the next stage once promotion criteria such as tests or scans are met. If you plan to containerize your Go microservice, the same principle applies: build each Docker image once and promote it through a series of staging repositories. In this way, you can guarantee that what was tested is exactly what is being released to production.

Build Promotion

5. Avoid Monolithic Pipelines

Instead of a single, monolithic pipeline for your app, It’s better to have several, with each one building, testing, scanning and promoting a different layer. This helps make your CI/CD process more flexible, with different teams responsible for each layer, and fosters a “fail fast” system that helps catch errors early.

For example, deploying a containerized application can typically be composed of five pipelines:

alpine:3.10

Artifactory acts as your “source of truth” for your Go builds, providing a GOPROXY for both public and private modules, as well as storing compiled binaries. Using the JFrog CLI to build your Go app helps the build process interact with Artifactory, and capture the build info that makes your builds fully traceable. Here is a sample snippet:

 

To explore this more, take a look at our example demonstration files for GoLang CI/CD  that we’ll be using at GopherCon.

As you can see, some simple best practices in managing your GoLang applications can ease the way to effective CI/CD. And Artifactory, as the essential manager of your software artifact supply chain, can play a central role in helping to bring those methods into your software development pipeline.

Any questions? We’ll be happy to answer them at Gophercon; dive in with us to explore all the best ways to release your Go applications fast, and at top quality. Or you can start trying to put them into practice with a free trial of Artifactory!