Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jobs/instances-snapshot/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Using apline/golang image
FROM golang:1.22-alpine
FROM golang:1.23-alpine

# Set destination for COPY
WORKDIR /app
Expand Down
22 changes: 16 additions & 6 deletions jobs/instances-snapshot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This example is very simple, it generates snapshots of your desired Instance.
## Step 1 : Build and push to Container registry

Serverless Jobs, like Serverless Containers (which are suited for HTTP applications), works
with Containers. So first, using your terminal reach this folder and run the following commands:
with containers. So first, use your terminal reach this folder and run the following commands:

```shell
# First command is to login to container registry, you can find it in Scaleway console
Expand All @@ -24,14 +24,16 @@ docker login rg.fr-par.scw.cloud/jobs-snapshot -u nologin --password-stdin <<< "
# Here we build the image to push
docker build -t rg.fr-par.scw.cloud/jobs-snapshot/jobs-snapshot:v1 .

## TIP: for Apple Silicon or other ARM processors, please use the following command as Serverless Jobs supports amd64 architecture
# docker buildx build --platform linux/amd64 -t rg.fr-par.scw.cloud/jobs-snapshot/jobs-snapshot:v1 .

# Push the image online to be used on Serverless Jobs
docker push rg.fr-par.scw.cloud/jobs-snapshot/jobs-snapshot:v1
```
> [!TIP]
> As we do not expose a web server and we do not require features such as auto-scaling, Serverless Jobs are perfect for this use case.

Note about Serverless Containers versus Serverless Jobs. As we do not expose a web server and we do not
require features such as auto-scaling, Serverless Jobs are perfect for this use case.

To check if everyting is ok, on the Console you can verify if your tag is present in Container Registry.
To check if everyting is ok, on the Scaleway Console you can verify if your tag is present in Container Registry.

## Step 2: Creating the Job Definition

Expand All @@ -44,25 +46,33 @@ On Scaleway Console on the following link you can create a new Job Definition: h
1. To schedule your job for example every night at 2am, you can set the cron to `0 2 * * *`.
1. Important: advanced option, you need to set the following environment variables:

> [!TIP]
> For sensitive data like `SCW_ACCESS_KEY` and `SCW_SECRET_KEY` we recommend to inject them via Secret Manager, [more info here](https://www.scaleway.com/en/docs/serverless/jobs/how-to/reference-secret-in-job/).

- `INSTANCE_ID`: grab the instance ID you want to create snapshots from
- `INSTANCE_ZONE`: you need to give the ZONE of you instance, like `fr-par-2`
- `SCW_ACCESS_KEY`: your access key
- `SCW_SECRET_KEY`: your secret key
- `SCW_DEFAULT_ORGANIZATION_ID`: your organzation ID

1. Click "create job"
* Then click "create job"

## Step 3: Run the job

On your created Job Definition, just click the button "Run Job" and within seconds it should be successful.

## Troubleshooting

If your Job Run state goes in error, you can use the "Logs" tab in Scaleway Console to get more informations about the error.

# Possible improvements

You can exercice by adding the following features:

- Instead of managing a single instance, make it account wide
- Add disk backups
- Add alerts if something goes wrong
- Use secret manager instead of job environment variables

# Additional content

Expand Down
4 changes: 2 additions & 2 deletions jobs/instances-snapshot/go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/scaleway/serverless-examples/jobs/instances-snapshot

go 1.22.2
go 1.23

require github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21
require github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32

require gopkg.in/yaml.v2 v2.4.0 // indirect
4 changes: 2 additions & 2 deletions jobs/instances-snapshot/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32 h1:4+LP7qmsLSGbmc66m1s5dKRMBwztRppfxFKlYqYte/c=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.32/go.mod h1:kzh+BSAvpoyHHdHBCDhmSWtBc1NbLMZ2lWHqnBoxFks=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
Expand Down
54 changes: 30 additions & 24 deletions jobs/instances-snapshot/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,33 @@ package main
import (
"fmt"
"os"
"time"

"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
)

const (
envOrgID = "SCW_DEFAULT_ORGANIZATION_ID"
envAccessKey = "SCW_ACCESS_KEY"
envSecretKey = "SCW_SECRET_KEY"
envInstanceID = "INSTANCE_ID"
envInstanceZone = "INSTANCE_ZONE"
)

func main() {
fmt.Println("creating snapshot of instance...")

// Create a Scaleway client with credentials from environment variables.
client, err := scw.NewClient(
// Get your organization ID at https://console.scaleway.com/organization/settings
scw.WithDefaultOrganizationID(os.Getenv("SCW_DEFAULT_ORGANIZATION_ID")),
scw.WithDefaultOrganizationID(os.Getenv(envOrgID)),

// Get your credentials at https://console.scaleway.com/iam/api-keys
scw.WithAuth(os.Getenv("SCW_ACCESS_KEY"), os.Getenv("SCW_SECRET_KEY")),
scw.WithAuth(os.Getenv(envAccessKey), os.Getenv(envSecretKey)),

// Get more about our availability zones at https://www.scaleway.com/en/docs/console/my-account/reference-content/products-availability/
// Get more about our availability
// zones at https://www.scaleway.com/en/docs/console/my-account/reference-content/products-availability/
scw.WithDefaultRegion(scw.RegionFrPar),
)
if err != nil {
Expand All @@ -43,40 +53,36 @@ func createSnapshots(instanceAPI *instance.API) error {
return fmt.Errorf("error while getting instance %w", err)
}

now := time.Now().Format(time.DateOnly)

for _, volume := range gotInstance.Server.Volumes {
snapshotName := fmt.Sprintf("snap-vol-%s-%s-%s",
volume.VolumeType.String(),
now,
os.Getenv(envInstanceZone))

snapshotResp, err := instanceAPI.CreateSnapshot(&instance.CreateSnapshotRequest{
Name: volume.Name + RandomString(4),
Name: snapshotName,
VolumeID: &volume.ID,
VolumeType: instance.SnapshotVolumeTypeBSSD,
Zone: scw.Zone(os.Getenv("INSTANCE_ZONE")),
VolumeType: instance.SnapshotVolumeType(volume.VolumeType),
Zone: scw.Zone(os.Getenv(envInstanceZone)),
})
if err != nil {
return fmt.Errorf("error while creating snapshopt %w", err)
return fmt.Errorf("error while creating snapshot %w", err)
}

fmt.Println("created snapshot ", snapshotResp.Snapshot.ID)
}

return nil
}

func init() {
if os.Getenv("SCW_DEFAULT_ORGANIZATION_ID") == "" {
panic("missing SCW_DEFAULT_ORGANIZATION_ID")
}
mandatoryVariables := [...]string{envOrgID, envAccessKey, envSecretKey, envInstanceID, envInstanceZone}

if os.Getenv("SCW_ACCESS_KEY") == "" {
panic("missing SCW_ACCESS_KEY")
}

if os.Getenv("SCW_SECRET_KEY") == "" {
panic("missing SCW_SECRET_KEY")
}

if os.Getenv("INSTANCE_ID") == "" {
panic("missing INSTANCE_ID")
}

if os.Getenv("INSTANCE_ZONE") == "" {
panic("missing INSTANCE_ZONE")
for idx := range mandatoryVariables {
if os.Getenv(mandatoryVariables[idx]) == "" {
panic("missing environment variable " + mandatoryVariables[idx])
}
}
}
21 changes: 0 additions & 21 deletions jobs/instances-snapshot/string.go

This file was deleted.

Loading