Go on z/OS - Group home

Go and Containers on z/OS


Since their introduction, containers have been a main part of application development due to their portability and efficiency. With the release of the z/OS Containers Platform (zOSCP) 1.1, developers on z/OS can now leverage these benefits as well. And with the release of IBM Open Enterprise SDK for Go 1.22, we're very excited to announce that Go on z/OS will be a supported language for use in containers. This blog will go over how you can get started with Go in a container and how you can verify the Go on z/OS image.


There are a few things you need to have before continuing:

  • A z/OS 3.1 system with z/OS UNIX System Services
    • A z/OS 2.5 system with the latest APARs will also work
  • The zOSCP suite of container tools - specifically Podman
  • An SMP/E license for the Open Enterprise SDK for Go and zOSCP that come with their respective entitlement keys
    • Entitlement keys should be found in the attached entitlement memos

The Go on z/OS team has created an image that contains the Go compiler. You cannot create a usable container with just this image as it is just a scratch image with some extra files. However by using the COPY directive in a containerfile, you can easily add the compiler to another image,  in this case it will be the base z/OS image. You can get the z/OS base image and the Go image by doing the following:

podman pull icr.io/zoscp/zos:latest --creds iamapikey:<zos base image entitlement key>
podman pull icr.io/zoscp/golang:latest --creds iamapikey:<go image entitlement key>

Creating a Go Container to Build and Run an Application 

To containerize your Go application, it can be done by creating a containerfile like the one below. Note that your application must be in the same directory as the containerfile. 

# choose the version of z/OS and Go – "latest" is recommended
FROM zos:latest
COPY --from=golang:latest /go /go

# Base work directory within the container

# Create script to run go with correct environment settings
RUN mkdir ./bin;echo '#/bin/sh\neval $(/go/etc/goz-env) >/dev/null\nexec /go/bin/go "$@"'>./bin/go;chmod 755 ./bin/go
ENV PATH="$PATH:./bin"

# Copy dependencies independently from building the application.
# This allows podman to cache this step for every build where
# the dependencies don't change.
COPY go.mod go.sum ./
RUN go mod download

# Build the Go application.
COPY *.go ./
RUN go build -o /<name of executable>

# Command to run on container initialization
CMD ["/<name of executable>"]

After creating the containerfile, build an image with podman build:

  • podman build -t mygoimage:myversion -f /path/to/containefile
    • If your containefile is using the default filename ("Containerfile") and is in your current working directory, you can omit the -f flag and use a "."
    • e.g. podman build -t myimage:myversion .

To create and run a container using your newly built image, run this command:

  • podman run -it --rm mygoimage:myversion
    • The -it flag will run the container interactively in a shell environment
    • The --rm` flag will remove the container after the container has stopped

Creating a Go Container for Development

This next image will be geared towards developing Go applications, thus you need to make some additions to your containerfile from the previous section. Most of these changes will involve adding directories and setting environment variables for the Go compiler. To make some quality of life improvements to your container environment, you will use z/OS Open Tools (Zopen Tools) to add bash, git, and make. In your current working directory, download the latest version of meta, at the time of writing it is 0.8.2. 

FROM zos
COPY --from=golang:latest /go /go

# Adding zopen to the image
ADD ./meta-0.8.2.pax.Z /meta-0.8.2.pax.Z

# Setting up the environment for Go

RUN mkdir ./bin;echo '#/bin/sh\neval $(/go/etc/goz-env) >/dev/null\nexec /go/bin/go "$@"'>./bin/go;chmod 755 ./bin/go
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" &&\
 chmod -R 1777 "$GOPATH" &&\
 mkdir /tmp/gotmp

# Set up zopen tools and install bash and git
RUN pax -rf /meta-0.8.2.pax.Z &&\
 cd /meta-0.8.2 &&\
 bin/zopen init -y &&\
 . /tmp/zopen/etc/zopen-config &&\
 cd &&\
 rm -rf /meta-0.8.2 /meta-0.8.2.pax.Z &&\
 zopen install bash git make -y

# Add Go, $GOBIN, and the Zopen tools to your path
ENV PATH="$PATH:/go/bin:$GOPATH/bin:/tmp/zopen/usr/local/bin"

CMD bash

You can create your image and container just like you did in the previous section:

podman build -t myDevImage:myversion -f /path/to/containerfile
podman run -it --rm myDevImage:myversion

Verifying the Image Signature

If you would like to verify the Go on z/OS image, you can follow these instructions on a Linux system:
1) Have GPG and Skopeo both installed
2) Make sure you have <CertAlias>.pub.asc, a file with this public key:



3) Create or update a /etc/containers/policy.json or file (e.g. ~/policy.json) with the following:

     "default": [
                    "": [{ "type": "signedBy", "keyType": "GPGKeys", "keyPath": "<public key>"}]

4) If you modified /etc/containers/policy.json

  • skopeo copy docker://icr.io/zoscp/golang:latest dir:<imagedir> --src-creds iamapikey:<entitlement key>

5) Try and validate using skopeo copy to a local temp directory with --policy option:

  • skopeo copy --policy ~/policy.json docker://icr.io/zoscp/golang:latest dir:./temp --src-creds iamapikey:<entitlement key>

6) Try validating during pull with Podman:

  • podman pull --signature-policy ~/policy.json icr.io/zoscp/golang:latest

If you would like to verify a local copy of the image, you can do the following:

1) Copy the image locally using Skopeo:

  • skopeo copy docker://icr.io/zoscp/golang:latest dir:<imagedir> --src-creds iamapikey:<entitlement key>

2) Import the public key to the GPG key store

  • gpg --import ./CertKeyAlias.pub.asc

3) Find the fingerprint for the key you just imported:

  • export FINGERPRINT=$(gpg --fingerprint --with-colons | grep fpr | tr -d 'fpr:')

4) Verify the image's signature:

  • skopeo standalone-verify <imagedir>/manifest.json icr.io/zoscp/golang:latest $FINGERPRINT <imagedir>/signature-1