How to Use JFrog Artifactory and GoCenter Together to Build Go Apps

 

UPDATE: As of May 1, 2021 – GoCenter central repository has been sunset and all features deprecated. For more information on the sunsetting of the centers read the Center deprecation blog post

As a cloud native programming language, Go is picking up steam quite rapidly. In the latest StackOverflow Insights survey, Go was named as the third most wanted language. Go also has a vibrant community that produces a pretty stellar list of Go apps and modules and with the rise of public registries, like GoCenter, you can have immutable dependencies too.

Why do we need Go modules?

Let’s start with a quick recap of some of my other blog posts on why we need Go modules in the first place. If you don’t use Go modules, but use vendoring instead, the time it takes to clone and build your project will increase making it more time-consuming to push your latest update to production. Without Go modules, your project will never truly have repeatable builds. You can build your project using version 1.2 of a module and the next morning someone else in your team might use version 1.3. If you depend on other software, it needs to immutable preventing developer, that decides to experiment a little, to make changes. Without Go modules, immutability cannot be guaranteed.

How to create a Go module?

Depending on where you put your source code you might need to set the environment variable GO111MODULE. From Go 1.11, it’s no longer recommended to put your source code in your $GOPATH. However, if you still choose to put your code in your $GOPATH and want to use Go modules you’ll have to set the GO111MODULE to on.

To create a Go module, run the following command: go mod init <name of your module>. For example, to create a module called “github.com/retgits/bla” the command would be go mod init github.com/retgits/bla

To get the template and create the outline of the app, you’ll need to run two commands:

module github.com/retgits/bla

go 1.12

You can now add Go modules you depend on by running “go get". Since you want to have immutable builds, you have two ways to get your modules from GoCenter and we’ll look at both of them:

  • Use a utility called goc, which builds Go apps using modules from GoCenter without requiring any need for manual setup;
  • Use Artifactory and set up a remote and virtual repository for your own modules together with the modules proxied from GoCenter.

Use goc to resolve modules from GoCenter

The goc utility automatically sets the GOPROXY environment variable to GoCenter. This means it bypasses other proxies like Artifactory. The current behavior of the Go client is to look at one single proxy and fail your build if not all modules are resolved from there. goc will look at GoCenter first and if the module isn’t in GoCenter it will get the module from its original place (like GitHub). Using goc is great if you only build open source software and don’t need to keep your own builds somewhere safe.

Use Artifactory to resolve your Go modules 

If you want to use Artifactory to resolve and cache your Go modules, you need to create a remote repository for GoCenter. The next step is to create a virtual repository that contains the remote repository for GoCenter. To resolve modules from Artifactory, you have two options. You can use either the GOPROXY environment variable or the JFrog CLI.

Option 1: Use GOPROXY

You can set your GOPROXY environment variable to point to your virtual repository (for example, export GOPROXY="https://<username>:<api key>@my.artifactory.server/artifactory/api/go/go" for a virtual repository called “go”).;

Using the GOPROXY environment variable has almost the same behavior as using goc. The Go client will try to resolve all Go modules from Artifactory. In turn, Artifactory will look at both its local and remote repositories to serve the modules to you. While this is excellent for pretty much all developers, the only thing you cannot do is publish new Go modules to Artifactory.

Option 2: Use the JFrog CLI

When you use the JFrog CLI to build your Go apps, it will work as a wrapper around the Go client. The JFrog CLI uses the Go client to try and resolve all Go modules from Artifactory. In turn, Artifactory will look at both its local and remote repositories and serve the modules to you. The JFrog CLI will also publish modules that aren’t in Artifactory yet to Artifactory so that they are available for future builds.

JFrog CLI v. 1.26.0 introduced a number of major changes to the way the JFrog CLI calls the Go client. Starting from this release, the exact same syntax that you use with the Go client is now supported which is excellent news for Go developers and DevOps engineers building Go pipelines. To start using this new syntax, and save you from typing the name of the Artifactory server and repository at the end of every command, run jfrog rt go-config which generates a yaml file with configuration data:

$ jfrog rt go-config

Set Artifactory server ID (press Tab for options) [myServer]: myServer

Set repository for dependencies resolution (press Tab for options): go

Deploy project dependencies to Artifactory (y/n) [y]? y

Set Artifactory server ID (press Tab for options) [myServer]: myServer

Set repository for dependencies deployment (press Tab for options): go

[Info] Go build config successfully created.

That means that running jfrog rt go build -ldflags=’-X “main.version=3″‘” will build your app, resolving all Go modules from the “go” repository on the “myServer” Artifactory instance. If you want to type even less, you could alias “jfrog rt go” to “go”. That saves you from making any changes to any scripts you have while making use of Artifactory to get your Go modules.

What’s next?

If you want to try these steps out too, but don’t want to make changes to your Artifactory servers, check out our test drive option. This will give you access to an Artifactory server, running in the cloud, for four days without requiring you to install anything on your local machine. As always, let me know your thoughts, comments, and feedback on Twitter!