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.

Prerequisites

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
WORKDIR /app

# 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
ENV GOTOOLCHAIN="path"\
 GOPATH="/tmp/go"\
 TMPDIR="/tmp/gotmp"

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:

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGXnMTwBEAC7SzXz5H86IpkRu0/7oHbikKDLQJWxmVv43P1pzCH41Ml3Bs9A
xXbo5U4vZxfi8b5HTjW0XPUZokdOqiEV9ILYr61bteN3D1Ni4zsi/SQSbzh+5j89
PNBAC/uj4Cr8OSGwHyZvyUZcdZQ96lft8TW/6gsYoq/GETWcH/kT06O6BUEObR4d
Gk0yPubJ8NwtwqATUCKfXfhnpO/NN/QxnbTGdC5v29Jz0RsKQ6pu1Xu2VrcU2/LV
FFhp5kBQ1ckAZwe1QhXYGWJILQSvgCLg+Ubzfg6w1cJvPecVvDobZqtaMfRpf6Ry
Yy4uTqdWhkAcQ9Dg5aUXFIFrWfof31hlQiNYYSvGLKCAgF7t8Nsy2/NkZLk4Ui1p
y2dljKDlHy5YFRC+fB7o+Lo7dg8znTDmZDQCzn0BJsNIFfGfL2tJ8CYlHfp9o6rF
wwiFnE/7MjnooZ2tbLcb5TIfyfvbHlAhzD5Xk56dMVyPKIKjhJhJ4JRPmdawPXIV
MvecN7KbPftFH+XS1pnscToo6e4h3rHo51lbqJbjuBJwQTuqvG8wJT/9TNOof3lx
B0x7ZBtY+Oz3nf6JjhBRmz4u5JR3XoyGM/xs6U+Yw140JDJKYEzB+5Nivz+MzIln
EWH55CAWMKKZacpb2/mCgBr6mdJyn9q/ljR7pP3SMvpJCICeUzjEQAV+dwARAQAB
tCZHT1ogY29udGFpbmVyIGltYWdlIDxwc2lydEB1cy5pYm0uY29tPokCOgQTAQgA
JAUCZecxPAIbDwULCQgHAgYVCgkICwIEFgIDAQIeAQUJAAAAAAAKCRD0h1RF3Fwq
WYfxEAC3UtNEdP0LyItxhY1aVhM3F9MHj3FfCT2EKFJrNQ2xw6cFlDrVyv8SC9Wj
Vn5E+VmVrn7bqL0qsZu7yt57eIJy4aFZ80ODkbBDsZMfL8qsfYSKOdLxyOMXq6Xs
ubsihaI1zl0rAqj3JIUGVfxsJKNkjdthQhRYcCfjuu4BUK86uqS9LuLVsYiOH1nZ
PCA4w6xPREd69flY3gWb0Ui0iGGX5hcQ3p5StjPOly3j+hjpKdh7A9h+yhpP/cMg
Em1aQHuzGZq87QBRhiaeQHw1k0VfyOd7t1PL0N79hnUTdSCc8lbQojHTxe/XizAI
BruKIg5nlBWscZGkdP3HmSBzUd4DOR3R0rnc/62aM7UEZcKu07wCGN0yg0MYqR8v
Ez9x8XuQH8XxOZog7Ah4ocCeJ8wRkpyodCHN1p2UI+0NttCGe6QV+aoG9fAJpnGD
QxO9NY8v1ewkUk28ytxo9BpX8uWhG2BDaxLWPOaA+FVrveAC5e6oSci5W3CEw87N
5qaWAQZxvxhxajY1ALc5xgNE1W5A1Uf9k6Xo3DG0nDW9cK1xl/bviHzaJvPr5BID
oIH3EDRiffh4aydVfDJZOEwoBUvXtNs+M3WcsAwvsU7ugJK8IbWk+Nq2Nj6bnHLE
iWXngH0u3XDTiRFJbAmb4tHxeHZES2EWoVD78MoDepDgw7TP5Q==
=HPD7
-----END PGP PUBLIC KEY BLOCK-----



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

{
     "default": [
        {
            "type":"reject"
        }
    ],
    "transports":
        {
            "docker":
                {
                    "": [{ "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