On-prem Backups: NAS and NFS, Minio, Fuse, Monitors and Synology CloudSync

Published: Sep 10, 2024 by Isaac Johnson

In our last two posts we explored Cloud-based backups. But what about on-prem? What choices do we have outside the major cloud providers?

Today we will look at using on-prem Synology NASes and how to set them up for NFS shares. We’ll explore Minio containerized and running on our NAS and then using Minio with s3fs for backups and syncing with cron.

Lastly, we’ll look at monitors using Datadog, OpenStatusand using Synology CloudSync to backup our NAS volumes to cloud storage such as GCP Buckets.

NAS

On-prem I keep two active Synology NAS appliances

/content/images/2024/09/nas-01.png

The newer device is a Synology DS220+ with 10Gb of Memory (which I upgraded myself) and 10Tb of Storage (Raid 1+0).

The older of the two is a DS216Play with 6 Tb, also Raid 1+0. I tend to use WD Red Drives and only recently did this one have some failures that required replacements of both within a month of each other - they had lasted WAY longer than the specs, nearly 8 years of heavy constant use.

Updates are easy

/content/images/2024/09/nas-02.png

Incurring a minor service blip as it restarts

/content/images/2024/09/nas-03.png

I just need to watch the page and see when it’s completed

/content/images/2024/09/nas-04.png

I’m not here to sell hardware, but I’m a fan of these and i think they’re quite excellent. my most important files, like photos are replicated between the two.

And for what it’s worth, I bought my last not from Amazon and instead from Microcenter. If I did it today, I would get the DS1522.

File shares

Knowing that my NAS(es) run the same basic OS, creating fileshares is pretty much identical between the two.

For instance, let’s say I desire a new block of space as a “Shared Folder” in the older NAS.

I can go to Shared Folders and click “Create”

/content/images/2024/09/nas-05.png

I’ll give it a name such as “linuxbackups”. I do not want soft-delete so I’ll disable the “Recycle Bin”

/content/images/2024/09/nas-06.png

I could encrypt the folder, but I won’t

/content/images/2024/09/nas-07.png

Once I confirm settings

/content/images/2024/09/nas-08.png

I can grant access to specific users

/content/images/2024/09/nas-09.png

Once created, I’ll edit the share so we can get to the NFS Permissions

/content/images/2024/09/nas-10.png

There in the “NFS Permissions” tab I’ll grant access to my local CIDR block for machines

/content/images/2024/09/nas-11.png

Don’t forget to save it to take effect

/content/images/2024/09/nas-12.png

Let’s say we want this for backups.

All I need to do is create a mount and an entry in fstab. Because my Dockerhost lives in the right CIDR, there is no need for user/pass authentication with NFS

builder@builder-T100:~$ sudo mkdir /mnt/linuxbackups
builder@builder-T100:~$ sudo vi /etc/fstab
builder@builder-T100:~$ tail -n1 /etc/fstab
192.168.1.129:/volume1/linuxbackups /mnt/linuxbackups nfs    auto,nofail,noatime,nolock,intr,tcp,actimeo=1800        0       0
builder@builder-T100:~$ sudo mount -a

Now to test by creating a text file

builder@builder-T100:~$ echo "this is a test" | sudo tee /mnt/linuxbackups/testfile.txt
this is a test

Which I see show up right away

/content/images/2024/09/nas-13.png

The fact is I’ve used this NAS for PostgreSQL backups for some time

builder@builder-T100:~$ cat /etc/fstab | grep 1.129
192.168.1.129:/volume1/postgres-prod-dbbackups  /mnt/psqlbackups nfs    auto,nofail,noatime,nolock,intr,tcp,actimeo=1800        0       0
192.168.1.129:/volume1/linuxbackups /mnt/linuxbackups nfs    auto,nofail,noatime,nolock,intr,tcp,actimeo=1800        0       0

We can see that writeup from May of 2023 here.

Minio and Docker Compose

The NAS does have the power to run docker

ijohnson@sirnasilot:~$ sudo docker ps
Password:
CONTAINER ID   IMAGE                           COMMAND                  CREATED         STATUS          PORTS
       NAMES
5fa76248b69d   portainer/portainer-ee:latest   "/portainer"             14 months ago   Up 27 minutes   0.0.0.0:8000->8000/tcp, :::8000->8000/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp, 9000/tcp   portaineree
83af22fb4b32   registry:latest                 "/entrypoint.sh /etc…"   14 months ago   Up 27 minutes   0.0.0.0:5050->5000/tcp, :::5050->5000/tcp
       registry-1

/content/images/2024/09/nas-14.png

This gave me the idea of using my newer NAS to actually run Minio in Docker (steps here)

As I want to clone the repo from Github, I need GIT installed.

I can actually use the Synology Package Center to install a GIT Server which includes the GIT binary

/content/images/2024/09/nas-15.png

I’ll clone the repo

ijohnson@sirnasilot:~$ git clone https://github.com/minio/minio.git
Cloning into 'minio'...
remote: Enumerating objects: 106651, done.
remote: Counting objects: 100% (24644/24644), done.
remote: Compressing objects: 100% (845/845), done.
remote: Total 106651 (delta 23994), reused 23848 (delta 23796), pack-reused 82007 (from 1)
Receiving objects: 100% (106651/106651), 125.70 MiB | 24.33 MiB/s, done.
Resolving deltas: 100% (77976/77976), done.

Then use Docker Compose to pull the images

ijohnson@sirnasilot:~$ cd minio/docs/orchestration/docker-compose/

ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo docker-compose pull
[+] Running 19/19
 ⠿ minio2 Skipped - Image is already being pulled by minio1                                                                                                                                  0.0s
 ⠿ minio3 Skipped - Image is already being pulled by minio1                                                                                                                                  0.0s
 ⠿ minio4 Skipped - Image is already being pulled by minio1                                                                                                                                  0.0s
 ⠿ minio1 Pulled                                                                                                                                                                            22.5s
   ⠿ 5f328c14e09d Pull complete                                                                                                                                                              3.7s
   ⠿ 7c0037c31c26 Pull complete                                                                                                                                                              5.8s
   ⠿ cb8ce3bb8f9a Pull complete                                                                                                                                                              7.3s
   ⠿ f4b17c317d15 Pull complete                                                                                                                                                             10.9s
   ⠿ 4cac341ffb02 Pull complete                                                                                                                                                             12.4s
   ⠿ a08f6ff4d495 Pull complete                                                                                                                                                             13.6s
   ⠿ 429760338d49 Pull complete                                                                                                                                                             14.3s
   ⠿ f5eabdee403e Pull complete                                                                                                                                                             15.2s
   ⠿ b8d89195f89b Pull complete                                                                                                                                                             15.9s
 ⠿ nginx Pulled                                                                                                                                                                             14.4s
   ⠿ df20fa9351a1 Pull complete                                                                                                                                                              0.9s
   ⠿ 3db268b1fe8f Pull complete                                                                                                                                                              3.1s
   ⠿ f682f0660e7a Pull complete                                                                                                                                                              5.4s
   ⠿ 7eb0e8838bc0 Pull complete                                                                                                                                                              7.0s
   ⠿ e8bf1226cc17 Pull complete             

I realized the first mistake when using docker-compose up was that I did not change the drive mounts

/content/images/2024/09/nas-16.png

So I stopped it

/content/images/2024/09/nas-17.png

I made some folders for “data1” and “data2”

ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data1-1
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data1-2
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data2-2
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data2-2
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data3-2
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data3-2
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data4-2
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo mkdir /volume1/minio/data4-2

I then gave it a real password and set the volumes correctly

ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ vi docker-compose.yaml
ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ cat docker-compose.yaml
version: '3.7'

# Settings and configurations that are common for all containers
x-minio-common: &minio-common
  image: quay.io/minio/minio:RELEASE.2024-08-29T01-40-52Z
  command: server --console-address ":9001" http://minio{1...4}/data{1...2}
  expose:
    - "9000"
    - "9001"
  environment:
    MINIO_ROOT_USER: admin
    MINIO_ROOT_PASSWORD: nottherealpassword
  healthcheck:
    test: ["CMD", "mc", "ready", "local"]
    interval: 5s
    timeout: 5s
    retries: 5

# starts 4 docker containers running minio server instances.
# using nginx reverse proxy, load balancing, you can access
# it through port 9000.
services:
  minio1:
    <<: *minio-common
    hostname: minio1
    volumes:
      - data1-1:/data1
      - data1-2:/data2

  minio2:
    <<: *minio-common
    hostname: minio2
    volumes:
      - data2-1:/data1
      - data2-2:/data2

  minio3:
    <<: *minio-common
    hostname: minio3
    volumes:
      - data3-1:/data1
      - data3-2:/data2

  minio4:
    <<: *minio-common
    hostname: minio4
    volumes:
      - data4-1:/data1
      - data4-2:/data2

  nginx:
    image: nginx:1.19.2-alpine
    hostname: nginx
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "9000:9000"
      - "9001:9001"
    depends_on:
      - minio1
      - minio2
      - minio3
      - minio4

## By default this config uses default local driver,
## For custom volumes replace with volume driver configuration.
volumes:
  data1-1:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data1-1
  data1-2:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data1-2
  data2-1:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data2-1
  data2-2:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data2-2
  data3-1:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data3-1
  data3-2:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data3-2
  data4-1:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data4-1
  data4-2:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: /volume1/minio/data4-2

I’m running interactive to start so I can debug any issues

ijohnson@sirnasilot:~/minio/docs/orchestration/docker-compose$ sudo docker-compose up
[+] Running 5/5
 ⠿ Container docker-compose-minio3-1  Recreated                                                                                                    5.8s
 ⠿ Container docker-compose-minio4-1  Recreated                                                                                                    7.5s
 ⠿ Container docker-compose-minio1-1  Recreated                                                                                                    6.5s
 ⠿ Container docker-compose-minio2-1  Recreated                                                                                                    7.4s
 ⠿ Container docker-compose-nginx-1   Recreated                                                                                                    2.0s
Attaching to docker-compose-minio1-1, docker-compose-minio2-1, docker-compose-minio3-1, docker-compose-minio4-1, docker-compose-nginx-1
docker-compose-minio3-1  | INFO: Waiting for at least 1 remote servers with valid configuration to be online
docker-compose-minio3-1  | INFO: Following servers are currently offline or unreachable [http://minio3:9000->http://minio4:9000 is unreachable: remote disconnected http://minio3:9000->http://minio1:9000 is unreachable: remote disconnected http://minio3:9000->http://minio2:9000 is unreachable: remote disconnected]
docker-compose-minio3-1  | INFO: Waiting for at least 1 remote servers with valid configuration to be online
docker-compose-minio3-1  | INFO: Following servers are currently offline or unreachable [http://minio3:9000->http://minio4:9000 is unreachable: remote disconnected http://minio3:9000->http://minio1:9000 is unreachable: remote disconnected http://minio3:9000->http://minio2:9000 is unreachable: remote disconnected]
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:05 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: no route to host (*net.OpError) Sleeping 795ms (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:05 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: connect: no route to host (*net.OpError) Sleeping 275ms (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  | INFO: Waiting for at least 1 remote servers with valid configuration to be online
docker-compose-minio3-1  | INFO: Following servers are currently offline or unreachable [http://minio3:9000->http://minio4:9000 is unreachable: remote disconnected http://minio3:9000->http://minio1:9000 is unreachable: remote disconnected http://minio3:9000->http://minio2:9000 is unreachable: remote disconnected]
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:07 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: i/o timeout (*net.OpError) Sleeping 0s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:07 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: i/o timeout (*net.OpError) Sleeping 0s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:07 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: i/o timeout (*net.OpError) Sleeping 0s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:07 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: i/o timeout (*net.OpError) Sleeping 0s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  | INFO: Waiting for at least 1 remote servers with valid configuration to be online
docker-compose-minio3-1  | INFO: Following servers are currently offline or unreachable [http://minio3:9000->http://minio4:9000 is unreachable: remote disconnected http://minio3:9000->http://minio2:9000 is unreachable: remote disconnected http://minio3:9000->http://minio1:9000 is unreachable: remote disconnected]
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:08 UTC 09/07/2024
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: connect: connection refused (*net.OpError) Sleeping 1.341s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  | INFO: Unable to use the drive http://minio1:9000/data1: drive not found, will be retried
docker-compose-minio3-1  | INFO: Unable to use the drive http://minio2:9000/data1: drive not found, will be retried
docker-compose-minio3-1  | INFO: Unable to use the drive http://minio1:9000/data2: drive not found, will be retried
docker-compose-minio3-1  | INFO: Unable to use the drive http://minio2:9000/data2: drive not found, will be retried
docker-compose-minio3-1  | INFO: Waiting for quorum READ healthcheck to succeed retrying in 28.326997ms.. possible cause unhealthy sets
docker-compose-minio3-1  | INFO: (Pool: 0 Set: 0 Healthy: false)
docker-compose-minio3-1  | INFO: Waiting for quorum READ healthcheck to succeed retrying in 218.712636ms.. possible cause unhealthy sets
docker-compose-minio3-1  | INFO: (Pool: 0 Set: 0 Healthy: false)
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:09 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: connect: connection refused (*net.OpError) Sleeping 1.592s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio4-1  | INFO: Unable to use the drive http://minio1:9000/data1: drive not found, will be retried
docker-compose-minio4-1  | INFO: Unable to use the drive http://minio2:9000/data1: drive not found, will be retried
docker-compose-minio4-1  | INFO: Unable to use the drive http://minio1:9000/data2: drive not found, will be retried
docker-compose-minio4-1  | INFO: Unable to use the drive http://minio2:9000/data2: drive not found, will be retried
docker-compose-minio4-1  | INFO: Waiting for all MinIO sub-systems to be initialize...
docker-compose-minio4-1  | INFO: Configured max API requests per node based on available memory: 712
docker-compose-minio4-1  | INFO: All MinIO sub-systems initialized successfully in 2.982574ms
docker-compose-minio4-1  | INFO: IAM load(startup) finished. (duration: 6.466975ms)
docker-compose-minio4-1  | ---------------------------
docker-compose-minio4-1  | MinIO Object Storage Server
docker-compose-minio4-1  | Copyright: 2015-2024 MinIO, Inc.
docker-compose-minio4-1  | License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
docker-compose-minio4-1  | Version: RELEASE.2024-08-29T01-40-52Z (go1.22.6 linux/amd64)
docker-compose-minio4-1  |
docker-compose-minio4-1  | API: http://172.18.0.3:9000  http://127.0.0.1:9000
docker-compose-minio4-1  | WebUI: http://172.18.0.3:9001 http://127.0.0.1:9001
docker-compose-minio4-1  |
docker-compose-minio4-1  | Docs: https://docs.min.io
docker-compose-minio4-1  | ---------------------------
docker-compose-minio3-1  | INFO: Waiting for all MinIO sub-systems to be initialize...
docker-compose-minio3-1  | INFO: Configured max API requests per node based on available memory: 719
docker-compose-minio3-1  | INFO: All MinIO sub-systems initialized successfully in 6.385275ms
docker-compose-minio3-1  | ---------------------------
docker-compose-minio3-1  | MinIO Object Storage Server
docker-compose-minio3-1  | Copyright: 2015-2024 MinIO, Inc.
docker-compose-minio3-1  | License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
docker-compose-minio3-1  | Version: RELEASE.2024-08-29T01-40-52Z (go1.22.6 linux/amd64)
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: http://172.18.0.2:9000  http://127.0.0.1:9000
docker-compose-minio3-1  | WebUI: http://172.18.0.2:9001 http://127.0.0.1:9001
docker-compose-minio3-1  |
docker-compose-minio3-1  | Docs: https://docs.min.io
docker-compose-minio3-1  | ---------------------------
docker-compose-minio3-1  | INFO: IAM load(startup) finished. (duration: 8.229168ms)
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:09 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: connect: connection refused (*net.OpError) Sleeping 1.276s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:10 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: i/o timeout (*net.OpError) Sleeping 0s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:10 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.05s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:10 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 605ms (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:10 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.068s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:11 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: connect: connection refused (*net.OpError) Sleeping 1.163s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:11 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio1:9000: dial tcp 172.18.0.4:9000: connect: connection refused (*net.OpError) Sleeping 1.769s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:11 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.423s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:11 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.907s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio1-1  | INFO: Unable to use the drive http://minio2:9000/data1: drive not found, will be retried
docker-compose-minio1-1  | INFO: Unable to use the drive http://minio2:9000/data2: drive not found, will be retried
docker-compose-minio1-1  | INFO: Waiting for all MinIO sub-systems to be initialize...
docker-compose-minio1-1  | INFO: Configured max API requests per node based on available memory: 705
docker-compose-minio1-1  | INFO: All MinIO sub-systems initialized successfully in 3.732779ms
docker-compose-minio1-1  | ---------------------------
docker-compose-minio1-1  | MinIO Object Storage Server
docker-compose-minio1-1  | Copyright: 2015-2024 MinIO, Inc.
docker-compose-minio1-1  | License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
docker-compose-minio1-1  | Version: RELEASE.2024-08-29T01-40-52Z (go1.22.6 linux/amd64)
docker-compose-minio1-1  |
docker-compose-minio1-1  | API: http://172.18.0.4:9000  http://127.0.0.1:9000
docker-compose-minio1-1  | WebUI: http://172.18.0.4:9001 http://127.0.0.1:9001
docker-compose-minio1-1  |
docker-compose-minio1-1  | Docs: https://docs.min.io
docker-compose-minio1-1  | ---------------------------
docker-compose-minio1-1  | INFO: IAM load(startup) finished. (duration: 3.435315ms)
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:12 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.022s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio1-1  |
docker-compose-minio1-1  | API: SYSTEM.grid
docker-compose-minio1-1  | Time: 11:44:13 UTC 09/07/2024
docker-compose-minio1-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio1-1  | Error: grid: http://minio1:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.291s (3) (*fmt.wrapError)
docker-compose-minio1-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio1-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio1-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio1-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio1-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio1-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:13 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.372s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio3-1  |
docker-compose-minio3-1  | API: SYSTEM.grid
docker-compose-minio3-1  | Time: 11:44:13 UTC 09/07/2024
docker-compose-minio3-1  | DeploymentID: 70f64fa5-5f0c-4b67-9d9b-5209ee42cdde
docker-compose-minio3-1  | Error: grid: http://minio3:9000 re-connecting to http://minio2:9000: dial tcp 172.18.0.5:9000: connect: connection refused (*net.OpError) Sleeping 1.246s (3) (*fmt.wrapError)
docker-compose-minio3-1  |        6: internal/logger/logonce.go:118:logger.(*logOnceType).logOnceIf()
docker-compose-minio3-1  |        5: internal/logger/logonce.go:149:logger.LogOnceIf()
docker-compose-minio3-1  |        4: internal/grid/connection.go:59:grid.gridLogOnceIf()
docker-compose-minio3-1  |        3: internal/grid/connection.go:672:grid.(*Connection).connect.func1()
docker-compose-minio3-1  |        2: internal/grid/connection.go:678:grid.(*Connection).connect()
docker-compose-minio3-1  |        1: internal/grid/connection.go:275:grid.newConnection.func3()
docker-compose-minio2-1  | INFO: Unable to use the drive http://minio1:9000/data1: drive not found, will be retried
docker-compose-minio2-1  | INFO: Unable to use the drive http://minio3:9000/data1: drive not found, will be retried
docker-compose-minio2-1  | INFO: Unable to use the drive http://minio1:9000/data2: drive not found, will be retried
docker-compose-minio2-1  | INFO: Unable to use the drive http://minio3:9000/data2: drive not found, will be retried
docker-compose-minio2-1  | INFO: Waiting for all MinIO sub-systems to be initialize...
docker-compose-minio2-1  | INFO: Configured max API requests per node based on available memory: 698
docker-compose-minio2-1  | INFO: All MinIO sub-systems initialized successfully in 6.797672ms
docker-compose-minio2-1  | ---------------------------
docker-compose-minio2-1  | MinIO Object Storage Server
docker-compose-minio2-1  | Copyright: 2015-2024 MinIO, Inc.
docker-compose-minio2-1  | License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
docker-compose-minio2-1  | Version: RELEASE.2024-08-29T01-40-52Z (go1.22.6 linux/amd64)
docker-compose-minio2-1  |
docker-compose-minio2-1  | API: http://172.18.0.5:9000  http://127.0.0.1:9000
docker-compose-minio2-1  | WebUI: http://172.18.0.5:9001 http://127.0.0.1:9001
docker-compose-minio2-1  |
docker-compose-minio2-1  | Docs: https://docs.min.io
docker-compose-minio2-1  | ---------------------------
docker-compose-minio2-1  | INFO: IAM load(startup) finished. (duration: 6.230698ms)

When it’s ready, we see at the end

docker-compose-minio2-1  | INFO: All MinIO sub-systems initialized successfully in 6.797672ms
docker-compose-minio2-1  | ---------------------------
docker-compose-minio2-1  | MinIO Object Storage Server
docker-compose-minio2-1  | Copyright: 2015-2024 MinIO, Inc.
docker-compose-minio2-1  | License: GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html
docker-compose-minio2-1  | Version: RELEASE.2024-08-29T01-40-52Z (go1.22.6 linux/amd64)
docker-compose-minio2-1  |
docker-compose-minio2-1  | API: http://172.18.0.5:9000  http://127.0.0.1:9000
docker-compose-minio2-1  | WebUI: http://172.18.0.5:9001 http://127.0.0.1:9001
docker-compose-minio2-1  |
docker-compose-minio2-1  | Docs: https://docs.min.io
docker-compose-minio2-1  | ---------------------------
docker-compose-minio2-1  | INFO: IAM load(startup) finished. (duration: 6.230698ms)
docker-compose-nginx-1   | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
docker-compose-nginx-1   | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
docker-compose-nginx-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
docker-compose-nginx-1   | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
docker-compose-nginx-1   | 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
docker-compose-nginx-1   | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
docker-compose-nginx-1   | /docker-entrypoint.sh: Configuration complete; ready for start up

I can now login

/content/images/2024/09/minionas-01.png

And see the dashboard

/content/images/2024/09/minionas-02.png

Before I go on, I want to stop the instance and then run as a daemon (background)

To use Minio, we need to create an access key

/content/images/2024/09/minionas-03.png

It will propose one, which looks fine to me. We can optionally set an expiry date as well

/content/images/2024/09/minionas-04.png

It then shows them once

/content/images/2024/09/minionas-05.png

and prompts for download as a JSON file.

builder@DESKTOP-QADGF36:~$ cat /mnt/c/Users/isaac/Downloads/credentials\ \(1\).json
{"url":"http://192.168.1.116:9001/api/v1/service-account-credentials","accessKey":"Oc3ZydYnG8fDWvWLPpTu","secretKey":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","api":"s3v4","path":"auto"}

I can now see I have a valid key

/content/images/2024/09/minionas-06.png

Next, to use this with S3 compliant tooling, I’ll need a bucket. We can create a Bucket from the Buckets section under Administrator.

I’ll create a Bucket for databasebackups. I will not enable versioning, but for things you wish to be extra safe on, you could enable it

/content/images/2024/09/minionas-07.png

I now have a “Database Backups” bucket ‘databasebackups”

/content/images/2024/09/minionas-08.png

Usage

I’ll add the secret access key and secret to my ~/.aws/credentials file

builder@DESKTOP-QADGF36:~$ vi ~/.aws/credentials
builder@DESKTOP-QADGF36:~$ cat ~/.aws/credentials | tail -n3
[miniosirnasilot]
aws_access_key_id = Oc3ZydYnG8fDWvWLPpTu
aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

We can now use that with the AWS CLI

builder@DESKTOP-QADGF36:~$ aws --profile miniosirnasilot --endpoint-url http://192.168.1.116:9000 s3 ls s3://databasebackups/
builder@DESKTOP-QADGF36:~$ aws --profile miniosirnasilot --endpoint-url http://192.168.1.116:9000 s3 ls
2024-09-07 06:57:55 databasebackups

I’ll admit I did two mistakes first, but in case others do the same:

First, I forgot that this is HTTP not HTTPS and saw SSL errors till I realized i left the ‘s’ in the URL

builder@DESKTOP-QADGF36:~$ aws --endpoint-url https://192.168.1.116:9000 s3 ls

SSL validation failed for https://192.168.1.116:9000/ [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1145)

And I also forgot to add “–profile” so it picked up my default AWS creds

builder@DESKTOP-QADGF36:~$ aws --endpoint-url http://192.168.1.116:9000 s3 ls

An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The Access Key Id you provided does not exist in our records.

Minio with Fuse

We can use Minio just like any S3 bucket in AWS.

For instance, let’s add s3fs to the dockerhost

builder@builder-T100:~$ sudo apt install s3fs
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
  apg gnome-control-center-faces gnome-online-accounts libcolord-gtk1 libfreerdp-server2-2 libgnome-bg-4-1 libgsound0
  libgssdp-1.2-0 libgupnp-1.2-1 libgupnp-av-1.0-3 libgupnp-dlna-2.0-4 libntfs-3g89 librygel-core-2.6-2 librygel-db-2.6-2
  librygel-renderer-2.6-2 librygel-server-2.6-2 libvncserver1 mobile-broadband-provider-info network-manager-gnome
  python3-macaroonbakery python3-protobuf python3-pymacaroons python3-rfc3339 python3-tz rygel
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
  s3fs
0 upgraded, 1 newly installed, 0 to remove and 166 not upgraded.
Need to get 297 kB of archives.
After this operation, 794 kB of additional disk space will be used.
Get:1 http://us.archive.ubuntu.com/ubuntu jammy/universe amd64 s3fs amd64 1.90-1 [297 kB]
Fetched 297 kB in 0s (757 kB/s)
Selecting previously unselected package s3fs.
(Reading database ... 316316 files and directories currently installed.)
Preparing to unpack .../archives/s3fs_1.90-1_amd64.deb ...
Unpacking s3fs (1.90-1) ...
Setting up s3fs (1.90-1) ...
Processing triggers for man-db (2.10.2-1) ...

I’ll now make a mount just for the S3 backend to my NAS

builder@builder-T100:~$ sudo mkdir /mnt/s3fs-dbbackups

I’ll need to make a credentials file with “ACCESSKEY:SECRET”

builder@builder-T100:~$ vi minio.credentials
builder@builder-T100:~$ cat minio.credentials
Oc3ZydYnG8fDWvWLPpTu:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
builder@builder-T100:~$ sudo chmod 600 minio.credentials

I can then add an entry in my fstab file

builder@builder-T100:~$ sudo vi /etc/fstab
builder@builder-T100:~$ cat /etc/fstab | tail -n1
databasebackups        /mnt/s3fs-dbbackups    fuse.s3fs       _netdev,allow_other,url=http://192.168.1.116:9000/,passwd_file=minio.credentials,use_path_request_style,uid=1000,gid=1000,umask=0001 0 0

And mount with sudo mount -a

Let’s create a test file

builder@builder-T100:~$ ls /mnt/s3fs-dbbackups/
builder@builder-T100:~$ echo "This is a test" | sudo tee /mnt/s3fs-dbbackups/testfile.txt
This is a test
builder@builder-T100:~$ ls /mnt/s3fs-dbbackups/
testfile.txt

Even though I do not see the object yet reflected in the Minio UI

/content/images/2024/09/minionas-09.png

I do see it if I hop over to a different host (my WSL) and list contents

builder@DESKTOP-QADGF36:~/Workspaces$ aws --profile miniosirnasilot --endpoint-url http://192.168.1.116:9000 s3 ls s3://databasebackups/
2024-09-07 07:25:05         15 testfile.txt

/content/images/2024/09/minionas-09.png

However, in a few minutes I did see the UI show we had an object

/content/images/2024/09/minionas-10.png

Minio Monitors

We can see some metrics in Monitoring

/content/images/2024/09/minionas-11.png

One useful feature is “Trace” that can identify what is being accessed in Minio

/content/images/2024/09/minionas-12.png

There are many more features such as bitrot scanners and compression settings

/content/images/2024/09/minionas-13.png

As my NAS has pretty good on-device compression, it would be redundant and I don’t want to burden docker with that.

However, I really want to get alerted if there is a problem. Let’s go to Uptime Kuma and add a check

/content/images/2024/09/minionas-14.png

I’ll monitor the Web UI port 9001 and set it to alert in all my ways

/content/images/2024/09/minionas-15.png

However, I had one minor issue recently - my Dockerhost seized and that meant Uptime Kuma stopped running. So fundamentally I’ll need something external to monitor.

Let’s add a Datadog Infrastructure agent to watch this host. I’ll add the APM instrumentation (though it is in Beta)

/content/images/2024/09/minionas-16.png

I can now launch that on my Dockerhost

builder@builder-T100:~$ DD_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx DD_SITE="datadoghq.com" DD_APM_INSTRUMENTATION_ENABLED=host DD_APM_INSTRUMENTATION_LIBRARIES=java:1,python:2,js:5,dotnet:2,ruby:2 bash -c "$(curl -L https://install.datadoghq.com/scripts/install_script_agent7.sh)"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 74650  100 74650    0     0   223k      0 --:--:-- --:--:-- --:--:--  224k

* Datadog Agent 7 install script v1.34.0

/usr/bin/systemctl

* Installing apt-transport-https, curl and gnupg

Hit:1 https://download.docker.com/linux/ubuntu focal InRelease
Hit:2 https://packages.microsoft.com/repos/azure-cli focal InRelease
Hit:3 http://us.archive.ubuntu.com/ubuntu jammy InRelease
Hit:4 https://packages.cloud.google.com/apt gcsfuse-jammy InRelease
Get:5 http://security.ubuntu.com/ubuntu jammy-security InRelease [129 kB]
Get:6 http://us.archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Hit:7 http://us.archive.ubuntu.com/ubuntu jammy-backports InRelease
Ign:8 https://packages.cloud.google.com/apt kubernetes-xenial InRelease
Err:9 https://packages.cloud.google.com/apt kubernetes-xenial Release
  404  Not Found [IP: 142.250.190.46 443]
Reading package lists...
W: https://packages.cloud.google.com/apt/dists/gcsfuse-jammy/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
E: The repository 'https://apt.kubernetes.io kubernetes-xenial Release' no longer has a Release file.
'apt-get update' failed, the script will not install the latest version of apt-transport-https.
Reading package lists...
Building dependency tree...
Reading state information...
curl is already the newest version (7.81.0-1ubuntu1.17).
gnupg is already the newest version (2.2.27-3ubuntu2.1).
The following packages were automatically installed and are no longer required:
  apg gnome-control-center-faces gnome-online-accounts libcolord-gtk1
  libfreerdp-server2-2 libgnome-bg-4-1 libgsound0 libgssdp-1.2-0
  libgupnp-1.2-1 libgupnp-av-1.0-3 libgupnp-dlna-2.0-4 libntfs-3g89
  librygel-core-2.6-2 librygel-db-2.6-2 librygel-renderer-2.6-2
  librygel-server-2.6-2 libvncserver1 mobile-broadband-provider-info
  network-manager-gnome python3-macaroonbakery python3-protobuf
  python3-pymacaroons python3-rfc3339 python3-tz rygel
Use 'sudo apt autoremove' to remove them.
The following packages will be upgraded:
  apt-transport-https
1 upgraded, 0 newly installed, 0 to remove and 165 not upgraded.
Need to get 1,510 B of archives.
After this operation, 0 B of additional disk space will be used.
Get:1 http://us.archive.ubuntu.com/ubuntu jammy-updates/universe amd64 apt-transport-https all 2.4.12 [1,510 B]
Fetched 1,510 B in 0s (10.1 kB/s)
(Reading database ... 316323 files and directories currently installed.)
Preparing to unpack .../apt-transport-https_2.4.12_all.deb ...
Unpacking apt-transport-https (2.4.12) over (2.4.11) ...
Setting up apt-transport-https (2.4.12) ...

... snip ...

No datadog.yaml file detected, not starting the agent
W: --force-yes is deprecated, use one of the options starting with --allow instead.

* Adding your API key to the Datadog Agent configuration: /etc/datadog-agent/datadog.yaml


* Setting SITE in the Datadog Agent configuration: /etc/datadog-agent/datadog.yaml

/usr/bin/systemctl
* Starting the Datadog Agent...

  Your Datadog Agent is running and functioning properly.
  It will continue to run in the background and submit metrics to Datadog.
  If you ever want to stop the Datadog Agent, run:

      sudo systemctl stop datadog-agent

  And to run it again run:

      sudo systemctl start datadog-agent

  Consider adding dd-agent to the docker group to enable the docker support, run:

      sudo usermod -a -G docker dd-agent

builder@builder-T100:~$

I can now see my host in Datadog

/content/images/2024/09/minionas-17.png

Including stats like traffic, disk, memory and CPU

/content/images/2024/09/minionas-18.png

I’ll next want to configure a host monitor

/content/images/2024/09/minionas-19.png

I set it to the Docker host and increased the time from the default 2 minutes to 10

/content/images/2024/09/minionas-20.png

For notifications, I’ll going to use Email and Pagerduty

/content/images/2024/09/minionas-21.png

I also plan to up the re-notification to every 12hours and stop after 5 occurrences.

/content/images/2024/09/minionas-22.png

Once saved, I can now see my Monitor is active and healthy

/content/images/2024/09/minionas-23.png

I noticed I didn’t see containers for my host

/content/images/2024/09/minionas-24.png

I then added:

container_image:
  enabled: true

To my datadog.yaml file and told it to restart

builder@builder-T100:~$ sudo vi /etc/datadog-agent/datadog.yaml
builder@builder-T100:~$ sudo systemctl restart datadog-agent
builder@builder-T100:~$

Even with the process_config enabled two ways

/content/images/2024/09/minionas-25.png

I never did see processes

/content/images/2024/09/minionas-26.png

Nor containers

/content/images/2024/09/minionas-27.png

OpenStatus

There is another way - and we can stay in the free tier.

I use OpenStatus to monitor my AWX instance today

/content/images/2024/09/minionas-28.png

In the free tier we can have really just one monitor and email

/content/images/2024/09/minionas-29.png

That said, my colleague Tristan could create a simple check for the Uptime endpoint

/content/images/2024/09/minionas-30.png

With the email being our PagerDuty

/content/images/2024/09/minionas-31.png

I can also create a status page

/content/images/2024/09/minionas-32.png

Which we can see here: fbs-uptime.openstatus.dev similar to FB Status.

So now I have UptimeKuma as a containerized monitor for all my systems and then OpenStatus and Datadog to monitor my Dockerhost in case that goes down. All this is in support of ensuring my containerized Minio is alive and well.

Synology Cloud Sync

I can install “Cloud Sync” as a package on the NAS itself

/content/images/2024/09/minionas-33.png

There are a lot of providers listed

/content/images/2024/09/minionas-34.png

/content/images/2024/09/minionas-35.png

I can see what permissions it needs, for instance, to use GCP Cloud Storage

/content/images/2024/09/minionas-36.png

Once I pick a project, I can see the GCP Buckets in the project

/content/images/2024/09/minionas-37.png

I can pick our Fuse test bucket

/content/images/2024/09/minionas-38.png

For instance, I can create a folder an initiate a sync directly from the NAS

Summary

We have covered so many ways to do local and remote backups at this point I should hope one of the patterns would work for most scenarios you may encounter.

Just focusing on GCP, for instance, we looked at Fuse, GSutil with Cron, the Storage Transfer Service and lastly the Cloud Sync app in Synology for On-prem backups to cloud

/content/images/2024/09/minionas-40.png

We also touched on monitors, from Uptime Kuma to OpenStatus to Datadog - with the idea that we can trigger alerts via Pagerduty.

We took a look at Minio finally, this time hosted via Docker on the NAS itself. We then could use the Cloud Sync app on Synology to sync to GCP. This is a wild way we could expose both on-prem storage (Volume in the local NAS) and backups to GCP while using AWS S3 compliant endpoints (Minio).

The reason we do this is sometimes there are solid tools out there from Longhorn storage to GlusterFS that easy can use S3 as backends

Cloud Storage Backups GCP Synology

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes