/docker-volume-gc-storage

Docker Volume Plugin for Google Cloud Storage (Buckets)

Primary LanguageGo

Docker Volume Plugin: Google Cloud Storage

Reserving up front a persistent disk of several 10s of GB might not seem like the best idea for some simple container use cases, let's look at an on-demand elastic bucket storage platform: Google Cloud Storage.

Overview

The goal is to use a storage bucket as a docker volume:

  • a volume would be accessible to containers running on different hosts (maybe not from same cloud provider, or even on local VM, or "native" containers on Mac)
  • direct access to the volume from the Google Cloud Storage web platform

Screencast - Youtube video

screencast_picture

File System

Any volume needs to expose a file system to handle the "disk" I/O, however a storage bucket does not expose any.
Solution: Google Cloud Platform gcsfuse:
Cloud Storage FUSE is an open source Fuse adapter that allows you to mount Google Cloud Storage buckets as file systems on Linux or OS X systems

Installation

Install Google Cloud Platform gcsfuse

https://github.com/GoogleCloudPlatform/gcsfuse/blob/master/docs/installing.md

Install the Volume Driver

$ go get github.com/craimbert/docker-volume-gc-storage
$ go install github.com/craimbert/docker-volume-gc-storage

Stop Docker engine (Debian)

$ service docker stop

Generate on GCP a Service Account key in JSON format

Section To generate a private key in JSON or PKCS12 format:
https://cloud.google.com/storage/docs/authentication?hl=en#generating-a-private-key

Start the Volume Driver (Debian)

$ docker-volume-gc-storage -gcp-key-json gcp-srv-account-key.json

Start Docker engine

$ service docker start

Usage

  • Create a volume
$ docker volume create --driver gcstorage --name datastore
datastore

The GCS Bucket name is defined by: gcsProjectID_volumeName

gcs-bucket-0

  • List volumes
$ docker volume ls
DRIVER              VOLUME NAME
gcstorage           datastore
  • Mount the volume on a container
$ docker run -it --rm -v datastore:/tmp alpine sh
/ # date > /tmp/date

The container dir /tmp is mounted on the GC Storage bucket defined by the volume datastore (through the host mountpoint /var/lib/docker-volumes/gcstorage/datastore/_data), the filesystem IO between host mountpoint and GCS bucket being handled by gcsfuse

gcs-bucket-1

Upload manually through Cloud Storage web portal a new foo file into the bucket:

gcs-bucket-2

Inside the container, the new file foo appears:

/tmp # ls -l /tmp/
total 1
-rw-r--r--    1 root     root            29 Jul  7 02:17 date
-rw-r--r--    1 root     root             4 Jul  7 03:50 foo

Useful Links

Google GO API

Docker Volume Driver interface

https://github.com/docker/go-plugins-helpers/blob/master/volume

##Tested environment: Go & Docker versions

$ go version
go version go1.6.2 linux/amd64

$ docker version
Client:
 Version:      1.11.2
 API version:  1.23
 Go version:   go1.5.4
 Git commit:   b9f10c9
 Built:        Wed Jun  1 21:23:39 2016
 OS/Arch:      linux/amd64
Server:
 Version:      1.11.2
 API version:  1.23
 Go version:   go1.5.4
 Git commit:   b9f10c9
 Built:        Wed Jun  1 21:23:39 2016
 OS/Arch:      linux/amd64

Common Issues

  • NTP needs to be running on the host in order to use Google APIs

TODO

On Docker for Mac: Docker engine doesn't seem to register the Volume Driver (even after engine restart):

$ docker volume create --driver gcstorage --name datastore
Error response from daemon: create datastore: create datastore: Error looking up volume plugin gcstorage: plugin not found
```
When actually the plugin seems to be referenced properly and behaves correctly (checking via HTTP Remote API):
```
$ cat /etc/docker/plugins/gcstorage.spec
tcp://127.0.0.1:8080

$ curl \
    -X POST \
    -d '{}' \
    http://127.0.0.1:8080/Plugin.Activate
{"Implements": ["VolumeDriver"]}

$ curl \
    -X POST \
    -d '{}' \
    http://127.0.0.1:8080/VolumeDriver.List

$ curl \
    -X POST \
    -d '{"Name": "datastore", "Opts": {}}' \
    http://127.0.0.1:8080/VolumeDriver.Create

$ curl \
    -X POST \
    -d '{}' \
    http://127.0.0.1:8080/VolumeDriver.List
{"Mountpoint":"","Err":"","Volumes":[{"Name":"datastore","Mountpoint":"/var/lib/docker-volumes/gcstorage/datastore/_data"}],"Volume":null,"Capabilities":{"Scope":""}}

$ curl \
    -X POST \
    -d '{"Name": "datastore"}' \
    http://127.0.0.1:8080/VolumeDriver.Get
{"Mountpoint":"","Err":"","Volumes":null,"Volume":{"Name":"datastore","Mountpoint":"/var/lib/docker-volumes/gcstorage/datastore/_data"},"Capabilities":{"Scope":""}}

$ tree /var/lib/docker-volumes/gcstorage
/var/lib/docker-volumes/gcstorage
└── datastore
    └── _data