Deploying with Go
Overview
There are three steps to deploy your application:
- Containerize your application by creating a
Dockerfile
- Modify
devfile.yaml
to add your Kubernetes code - Run
odo deploy
Prerequisites
Prerequisites:
In order to use odo deploy
you must be able to build an image as well as push to a registry.
Step 1. Login to your container registry
Login to a container registry that you will be pushing your application to:
- Podman
- Docker
podman login
$ podman login quay.io
Username:
Password:
Login Succeeded!
docker login
$ docker login docker.io
Username:
Password:
Login Succeeded!
Step 2. Set the appropriate container build platform
Your container image build must match the same architecture as the cluster you are deploying to.
For example: you will have to cross-build a AMD64 image on a Mac M1 (ARM64) in order to deploy to a AMD64 cluster.
odo
allows you to do so via the ODO_IMAGE_BUILD_ARGS
environment variable,
which is a semicolon-separated list of extra arguments to pass to Podman or Docker when building images.
Choose your deployment architecture:
- Linux (AMD64)
- Linux (ARM)
- Windows (AMD64)
export ODO_IMAGE_BUILD_ARGS="--platform=linux/amd64"
export ODO_IMAGE_BUILD_ARGS="--platform=linux/arm64"
export ODO_IMAGE_BUILD_ARGS="--platform=windows/amd64"
Step 1. Create the initial development application
Complete the Developing with Go guide before continuing.
Step 2. Containerize the application
In order to deploy our application, we must containerize it in order to build and push to a registry. Create the following Dockerfile
in the same directory:
# This Dockerfile is referenced from:
# https://github.com/GoogleCloudPlatform/golang-samples/blob/main/run/helloworld/Dockerfile
# Build
FROM golang:1.17-buster as builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . ./
RUN go build -v -o server
# Create a "lean" container
FROM debian:buster-slim
RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/server /app/server
# Run
CMD ["/app/server"]
Step 3. Modify the Devfile
Let's modify the devfile.yaml
and add the respective deployment code.
When copy/pasting to devfile.yaml
, make sure the lines you inserted are correctly indented.
odo deploy
uses Devfile schema 2.2.0. Change the schema to reflect the change:
# Deploy "kind" ID's use schema 2.2.0+
schemaVersion: 2.2.0
Add the variables
and change them appropriately:
# Add the following variables code anywhere in devfile.yaml
# This MUST be a container registry you are able to access
variables:
CONTAINER_IMAGE: quay.io/MYUSERNAME/go-odo-example
RESOURCE_NAME: my-go-app
CONTAINER_PORT: "8080"
DOMAIN_NAME: go.example.com
Add the commands used to deploy:
# This is the main "composite" command that will run all below commands
commands:
- id: deploy
composite:
commands:
- build-image
- k8s-deployment
- k8s-service
- k8s-url
group:
isDefault: true
kind: deploy
# Below are the commands and their respective components that they are "linked" to deploy
- id: build-image
apply:
component: outerloop-build
- id: k8s-deployment
apply:
component: outerloop-deployment
- id: k8s-service
apply:
component: outerloop-service
- id: k8s-url
apply:
component: outerloop-url
Add the Docker image location as well as Kubernetes Deployment and Service resources to components
:
components:
# This will build the container image before deployment
- name: outerloop-build
image:
dockerfile:
buildContext: ${PROJECT_SOURCE}
rootRequired: false
uri: ./Dockerfile
imageName: "{{CONTAINER_IMAGE}}"
# This will create a Deployment in order to run your container image across
# the cluster.
- name: outerloop-deployment
kubernetes:
inlined: |
kind: Deployment
apiVersion: apps/v1
metadata:
name: {{RESOURCE_NAME}}
spec:
replicas: 1
selector:
matchLabels:
app: {{RESOURCE_NAME}}
template:
metadata:
labels:
app: {{RESOURCE_NAME}}
spec:
containers:
- name: {{RESOURCE_NAME}}
image: {{CONTAINER_IMAGE}}
ports:
- name: http
containerPort: {{CONTAINER_PORT}}
protocol: TCP
resources:
limits:
memory: "1024Mi"
cpu: "500m"
# This will create a Service so your Deployment is accessible.
# Depending on your cluster, you may modify this code so it's a
# NodePort, ClusterIP or a LoadBalancer service.
- name: outerloop-service
kubernetes:
inlined: |
apiVersion: v1
kind: Service
metadata:
name: {{RESOURCE_NAME}}
spec:
ports:
- name: "{{CONTAINER_PORT}}"
port: {{CONTAINER_PORT}}
protocol: TCP
targetPort: {{CONTAINER_PORT}}
selector:
app: {{RESOURCE_NAME}}
type: NodePort
To be able to access our application we need to add one more component
to the Devfile.
For OpenShift cluster we add Route. For Kubernetes cluster we add Ingress.
- Kubernetes
- OpenShift
- name: outerloop-url
kubernetes:
inlined: |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{RESOURCE_NAME}}
spec:
rules:
- host: "{{DOMAIN_NAME}}"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: {{RESOURCE_NAME}}
port:
number: {{CONTAINER_PORT}}
- name: outerloop-url
kubernetes:
inlined: |
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: {{RESOURCE_NAME}}
spec:
path: /
to:
kind: Service
name: {{RESOURCE_NAME}}
port:
targetPort: {{CONTAINER_PORT}}
Your final Devfile should look something like this:
Your Devfile might slightly vary from the example below, but the example should give you an idea about the placements of all the components and commands.
- Kubernetes
- OpenShift
commands:
- exec:
commandLine: go build main.go
component: runtime
env:
- name: GOPATH
value: ${PROJECT_SOURCE}/.go
- name: GOCACHE
value: ${PROJECT_SOURCE}/.cache
group:
isDefault: true
kind: build
workingDir: ${PROJECT_SOURCE}
id: build
- exec:
commandLine: ./main
component: runtime
group:
isDefault: true
kind: run
workingDir: ${PROJECT_SOURCE}
id: run
# This is the main "composite" command that will run all below commands
- id: deploy
composite:
commands:
- build-image
- k8s-deployment
- k8s-service
- k8s-url
group:
isDefault: true
kind: deploy
# Below are the commands and their respective components that they are "linked" to deploy
- id: build-image
apply:
component: outerloop-build
- id: k8s-deployment
apply:
component: outerloop-deployment
- id: k8s-service
apply:
component: outerloop-service
- id: k8s-url
apply:
component: outerloop-url
components:
- container:
args:
- tail
- -f
- /dev/null
endpoints:
- name: http-go
targetPort: 8080
image: registry.access.redhat.com/ubi9/go-toolset:latest
memoryLimit: 1024Mi
mountSources: true
name: runtime
# This will build the container image before deployment
- name: outerloop-build
image:
dockerfile:
buildContext: ${PROJECT_SOURCE}
rootRequired: false
uri: ./Dockerfile
imageName: "{{CONTAINER_IMAGE}}"
# This will create a Deployment in order to run your container image across
# the cluster.
- name: outerloop-deployment
kubernetes:
inlined: |
kind: Deployment
apiVersion: apps/v1
metadata:
name: {{RESOURCE_NAME}}
spec:
replicas: 1
selector:
matchLabels:
app: {{RESOURCE_NAME}}
template:
metadata:
labels:
app: {{RESOURCE_NAME}}
spec:
containers:
- name: {{RESOURCE_NAME}}
image: {{CONTAINER_IMAGE}}
ports:
- name: http
containerPort: {{CONTAINER_PORT}}
protocol: TCP
resources:
limits:
memory: "1024Mi"
cpu: "500m"
# This will create a Service so your Deployment is accessible.
# Depending on your cluster, you may modify this code so it's a
# NodePort, ClusterIP or a LoadBalancer service.
- name: outerloop-service
kubernetes:
inlined: |
apiVersion: v1
kind: Service
metadata:
name: {{RESOURCE_NAME}}
spec:
ports:
- name: "{{CONTAINER_PORT}}"
port: {{CONTAINER_PORT}}
protocol: TCP
targetPort: {{CONTAINER_PORT}}
selector:
app: {{RESOURCE_NAME}}
type: NodePort
- name: outerloop-url
kubernetes:
inlined: |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{RESOURCE_NAME}}
spec:
rules:
- host: "{{DOMAIN_NAME}}"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: {{RESOURCE_NAME}}
port:
number: {{CONTAINER_PORT}}
metadata:
description: Go is an open source programming language that makes it easy to build
simple, reliable, and efficient software.
displayName: Go Runtime
icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg
language: Go
name: my-go-app
projectType: Go
provider: Red Hat
tags:
- Go
version: 1.0.2
# Deploy "kind" ID's use schema 2.2.0+
schemaVersion: 2.2.0
starterProjects:
- description: A Go project with a simple HTTP server
git:
checkoutFrom:
revision: main
remotes:
origin: https://github.com/devfile-samples/devfile-stack-go.git
name: go-starter
# Add the following variables code anywhere in devfile.yaml
# This MUST be a container registry you are able to access
variables:
CONTAINER_IMAGE: quay.io/MYUSERNAME/go-odo-example
RESOURCE_NAME: my-go-app
CONTAINER_PORT: "8080"
DOMAIN_NAME: go.example.com
commands:
- exec:
commandLine: go build main.go
component: runtime
env:
- name: GOPATH
value: ${PROJECT_SOURCE}/.go
- name: GOCACHE
value: ${PROJECT_SOURCE}/.cache
group:
isDefault: true
kind: build
workingDir: ${PROJECT_SOURCE}
id: build
- exec:
commandLine: ./main
component: runtime
group:
isDefault: true
kind: run
workingDir: ${PROJECT_SOURCE}
id: run
# This is the main "composite" command that will run all below commands
- id: deploy
composite:
commands:
- build-image
- k8s-deployment
- k8s-service
- k8s-url
group:
isDefault: true
kind: deploy
# Below are the commands and their respective components that they are "linked" to deploy
- id: build-image
apply:
component: outerloop-build
- id: k8s-deployment
apply:
component: outerloop-deployment
- id: k8s-service
apply:
component: outerloop-service
- id: k8s-url
apply:
component: outerloop-url
components:
- container:
args:
- tail
- -f
- /dev/null
endpoints:
- name: http-go
targetPort: 8080
image: registry.access.redhat.com/ubi9/go-toolset:latest
memoryLimit: 1024Mi
mountSources: true
name: runtime
# This will build the container image before deployment
- name: outerloop-build
image:
dockerfile:
buildContext: ${PROJECT_SOURCE}
rootRequired: false
uri: ./Dockerfile
imageName: "{{CONTAINER_IMAGE}}"
# This will create a Deployment in order to run your container image across
# the cluster.
- name: outerloop-deployment
kubernetes:
inlined: |
kind: Deployment
apiVersion: apps/v1
metadata:
name: {{RESOURCE_NAME}}
spec:
replicas: 1
selector:
matchLabels:
app: {{RESOURCE_NAME}}
template:
metadata:
labels:
app: {{RESOURCE_NAME}}
spec:
containers:
- name: {{RESOURCE_NAME}}
image: {{CONTAINER_IMAGE}}
ports:
- name: http
containerPort: {{CONTAINER_PORT}}
protocol: TCP
resources:
limits:
memory: "1024Mi"
cpu: "500m"
# This will create a Service so your Deployment is accessible.
# Depending on your cluster, you may modify this code so it's a
# NodePort, ClusterIP or a LoadBalancer service.
- name: outerloop-service
kubernetes:
inlined: |
apiVersion: v1
kind: Service
metadata:
name: {{RESOURCE_NAME}}
spec:
ports:
- name: "{{CONTAINER_PORT}}"
port: {{CONTAINER_PORT}}
protocol: TCP
targetPort: {{CONTAINER_PORT}}
selector:
app: {{RESOURCE_NAME}}
type: NodePort
- name: outerloop-url
kubernetes:
inlined: |
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: {{RESOURCE_NAME}}
spec:
path: /
to:
kind: Service
name: {{RESOURCE_NAME}}
port:
targetPort: {{CONTAINER_PORT}}
metadata:
description: Go is an open source programming language that makes it easy to build
simple, reliable, and efficient software.
displayName: Go Runtime
icon: https://raw.githubusercontent.com/devfile-samples/devfile-stack-icons/main/golang.svg
language: Go
name: my-go-app
projectType: Go
provider: Red Hat
tags:
- Go
version: 1.0.2
# Deploy "kind" ID's use schema 2.2.0+
schemaVersion: 2.2.0
starterProjects:
- description: A Go project with a simple HTTP server
git:
checkoutFrom:
revision: main
remotes:
origin: https://github.com/devfile-samples/devfile-stack-go.git
name: go-starter
# Add the following variables code anywhere in devfile.yaml
# This MUST be a container registry you are able to access
variables:
CONTAINER_IMAGE: quay.io/MYUSERNAME/go-odo-example
RESOURCE_NAME: my-go-app
CONTAINER_PORT: "8080"
Step 4. Run the odo deploy
command
Now we're ready to deploy our application on the cluster:
odo deploy
Sample Output
$ odo deploy
__
/ \__ Deploying the application using my-go-app Devfile
\__/ \ Namespace: odo-dev
/ \__/ odo version: v3.10.0
\__/
↪ Building & Pushing Container: quay.io/MYUSERNAME/go-odo-example
• Building image locally ...
build -t quay.io/MYUSERNAME/go-odo-example -f /home/user/quickstart-demo/go-demo/Dockerfile /home/user/quickstart-demo/go-demo
✓ Building image locally
• Pushing image to container registry ...
push quay.io/MYUSERNAME/go-odo-example
✓ Pushing image to container registry
↪ Deploying Kubernetes Component: my-go-app
✓ Creating resource Deployment/my-go-app
↪ Deploying Kubernetes Component: my-go-app
✓ Creating resource Service/my-go-app
↪ Deploying Kubernetes Component: my-go-app
✓ Creating resource Ingress/my-go-app
Your Devfile has been successfully deployed
Step 5. Accessing the application
You can now determine how to access the application by running odo describe component
:
odo describe component
Check for Kubernetes Ingresses if you are on a Kubernetes cluster or OpenShift Routes if you are an OpenShift cluster to obtain the URI for accessing your application.
Sample Output
- Kubernetes
- OpenShift
Name: my-go-app
Display Name: Go Runtime
Project Type: Go
Language: Go
Version: 1.0.2
Description: Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
Tags: Go
Running in: Deploy
Supported odo features:
• Dev: true
• Deploy: true
• Debug: false
Container components:
• runtime
Kubernetes components:
• outerloop-deployment
• outerloop-service
• outerloop-url
Kubernetes Ingresses:
• my-go-app: go.example.com/
Name: my-go-app
Display Name: Go Runtime
Project Type: Go
Language: Go
Version: 1.0.2
Description: Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
Tags: Go
Running in: Deploy
Supported odo features:
• Dev: true
• Deploy: true
• Debug: false
Container components:
• runtime
Kubernetes components:
• outerloop-deployment
• outerloop-service
• outerloop-url
OpenShift Routes:
• my-go-app: my-go-app-pvala-crt-dev.apps.sandbox-m2.ll9k.p1.openshiftapps.com/
Step 6. Delete the resources
After testing your application, you may optionally undeploy using the odo delete component
command:
odo delete component
Sample output
$ odo delete component
Searching resources to delete, please wait...
This will delete "my-go-app" from the namespace "odo-dev".
• The following resources will get deleted from cluster:
• - Deployment: my-go-app
• - Service: my-go-app
• - Ingress: my-go-app
? Are you sure you want to delete "my-go-app" and all its resources? Yes
✓ Deleting resources from cluster [65ms]
The component "my-go-app" is successfully deleted from namespace "odo-dev"