Overview #
In this tutorial I’m using the following setup based on Ubuntu 22.04 servers, GitLab is dockerized:
192.168.70.4 # GitLab
192.168.70.5 # GitLab Runner
192.168.70.6 # Deployment Server
I’m using the same setup for the deployment via SSH as described in my blog post:
GitLab CI Pipeline - Deploy website with Nginx Docker Container
The main requirements for the deployment via SSH key are the following:
-
Create a SSH key pair on the server where GitLab is deployed
-
Copy the public SSH key to the authorized keys file of the Deployment server
-
SSH into the deployment servers to add the fingerprint
-
Add the private SSH key as variable to the GitLab Repository CI/CD settings
-
On the deployment server, a user named “gitlab-deployment” is used for the authentication of for the GitLab CI pipeline
Deployment Server Prerequisites #
Deployment Folder #
Create a folder for the Go binary deployment:
# Create folder
sudo mkdir /go-binary
# Change the permissions
sudo chown -R gitlab-deployment:root /go-binary
GitLab Repository #
This GitLab repository is available on GitHub:
https://github.com/jueklu/compile-and-deploy-go-binary-via-scp
File & Folder Structure #
The file and folder structure of the GitLab repository looks like this:
GitLab-Repository
├── .gitlab-ci.yml
├── go.mod
├── main.go
└── README.md
CI Pipeline Manifest #
- .gitlab-ci.yml
# Variables that will be reused in the pipeline
variables:
DEPLOY_IP: "192.168.70.6" # Deployment server IP
DEPLOY_USER: "gitlab-deployment" # Deployment server SSH user
OUTPUT_DIR: go-bin # Directory to store the compiled binary
OUTPUT_NAME: $OUTPUT_DIR/example-binary_${CI_COMMIT_REF_SLUG} # Name of the binary (same as the project name)
# Pipeline stages
stages:
- compile
- deploy
### Compile Job
compile:
image: golang:latest
stage: compile
before_script: # Initialize the Go module environment
# Create directory for the compiled binary
- mkdir -p $OUTPUT_DIR
# Initialize a Go module if it doesn't already exist
- go mod init example-project || true
# Download dependencies (even if there are none, it's safe to run)
- go mod tidy
script: # Compile the Go binary and store it in the specified output directory
# Compile the Go program and output the binary to $OUTPUT_NAME
- go build -o $OUTPUT_NAME ./main.go
# List binary in the logs
- ls -la $OUTPUT_DIR
artifacts:
paths:
# Save the binary as an artifact for the next stage
- $OUTPUT_NAME
only:
- main
### Deploy Job
deploy:
stage: deploy
image: alpine:latest
before_script:
# Update the package index, install the OpenSSH client for SSH connections
- apk update && apk add openssh-client
# If the private SSH key file ($ID_RSA) exists, set secure permissions (read/write for the owner only)
- if [ -f "$ID_RSA" ]; then chmod og= $ID_RSA; fi
script:
# Copy the binary to the target Linux server
- scp -i $ID_RSA -o StrictHostKeyChecking=no $OUTPUT_NAME $DEPLOY_USER@$DEPLOY_IP:/go-binary
only:
- main
Go Source Code #
This Go code will just output “Hi there!” when executed.
main.go #
- main.go
// Declare the main package / required for any standalone executable Go program
package main
// Import the fmt package for formatted input/output functions
import "fmt"
// Define the main function, the entry point of the program
func main() {
fmt.Println("Hi there!") // Print the message to the console
}
go.mod #
- go.mod
module jueklu/some-go-project
go 1.21.8
Verify the Deployed Go Binary #
Verify the Binary #
Verify the file on the deployment server:
# List files
sudo ls /go-binary
# Shell output:
example-binary_main
Execute the Binary #
# Run the binary
sudo /go-binary/example-binary_main
# Shell output:
Hi there!