Uploading Blobs
Simple datastore
- tags
- docker
- golang
- effigy
Contents
I want a simple service I can deploy that lets me store blobs. I want it to return the hash of the stored object which I will use to load it again.
First we will write a simple go service that will do everything in memory, and then we will build a nginx config that has the webserver stream it to disk, so we don't have a lot of memory being used.
Simple go service
This is a simple http server that
- Creates a
blobs
directory - Serves
/get
requests out of that directory - Receives a file paramater named
file
on/put
and stores it as it's md5 hash. It returns that hash. - Or it gets a body and just stores it.
Server code
|
|
Server code orig
In simple/server.go
:
|
|
Testing
First start it up:
|
|
Then upload the file using curl -F
. We need to name the parameter
file
and use the @
syntax to push the file contents.
|
|
a03a16aa4ed93c7194c03bb3d759ba23
Which returns the has, then we can download it
|
|
KEY is a03a16aa4ed93c7194c03bb3d759ba23 -rw-r--r-- 1 wschenk wschenk 2227748 Feb 16 09:19 /tmp/talk.pdf a03a16aa4ed93c7194c03bb3d759ba23 /tmp/talk.pdf
Dockerizing
First we don't want to put the blobs into our docker image, so create
a .dockerignore
:
blobs/
Then a simple Dockerfile
:
|
|
And then build it:
|
|
And run it
|
|
NGINX uploader
This works fine, but it also requires loading everything into memory.
We can use nginx and the nginx-upload-module
to have the webserver
stream it directly to disk, and once this is done it will call our
handler which will move it over to the blobs
directory. This module
also computes the md5
for us, so that's nice an easy. But setting it
up is more complicated, and we'll need to use docker-compose.yml
to
wire everything together.
docker-compose.yml
to wire it all together- nginx
Dockerfile
default.conf
to configure the module- go mover
Dockerfile
- mover code
Let go!
docker-compose.yml
We'll define two services, which share a file system at /blobs
|
|
nginx Dockerfile
First we create a Dockerfile.nginx
to download the source for both
nginx
and nginx-upload-module
, build then, add it to the main
nginx.conf
file:
|
|
nginx default.config
Couple of things of note in this default.conf
file:
client_max_body_size | set to 2 gigs |
/get | serves from /blobs directly |
/put | Stores stuff into /blobs/upload and calls /mover on success |
error 415 | just post to /mover |
nginx | computes the mp5 hash |
|
|
mover Dockerfile.mover
This is a simple dockerfile that builds our go binary, and then just copies it over.
|
|
mover go code
All this really is doing is to look at the header and move the file around to the right path.
|
|
Setup
We don't really need this, but it's a good idea to make sure that the blobs don't go over as part of the build.
.dockerignore
:
blobs/
Lets create the blobs
folder, the upload
subdirectories, and make sure
that docker and read and write them:
|
|
Then start it all up with:
|
|
Testing
|
|
a03a16aa4ed93c7194c03bb3d759ba23
Which returns the has, then we can download it
|
|
KEY is a03a16aa4ed93c7194c03bb3d759ba23 -rw-r--r-- 1 wschenk wschenk 2227748 Feb 16 11:31 /tmp/talk.pdf a03a16aa4ed93c7194c03bb3d759ba23 /tmp/talk.pdf
Client examples
Bash posting data
|
|
c2a9ce57e8df081b4baad80d81868bbb
Bash posting file
We've already seen this:
|
|
a03a16aa4ed93c7194c03bb3d759ba23
Ruby posting data
client/ruby_data.rb
:
|
|
c2a9ce57e8df081b4baad80d81868bbb
Ruby posting data as a file
client/ruby_data_as_file.rb
:
|
|
c2a9ce57e8df081b4baad80d81868bbb
Ruby posting file
client/ruby_file.rb
:
|
|
a03a16aa4ed93c7194c03bb3d759ba23
node posting data
Requires node-fetch
npm package.
client/node_string.js
:
|
|
node posting string as file
Requires node-fetch
and form-data
packages:
client/node_string_as_file.js
:
|
|
node posting file
First we need to install some libraries:
|
|
Then:
|
|
Deno posting string
client/deno_string.ts
:
|
|
Deno posting string as file
client/deno_string_as_file.ts
:
|
|
Deno posting file
|
|
go posting string
client/go_string.go
:
|
|
go posting string as file
client/go_string_as_file.go
:
|
|
go posting file
client/go_string_as_file.go
:
|
|
Final thoughts
The reason that I wrote this is so that I could easily share large blobs of data between cloud functions without the overhead of installing a S3 clone or trying to jam stuff into Redis.
References
- https://gist.github.com/hermanbanken/96f0ff298c162a522ddbba44cad31081
- https://vsoch.github.io/2018/django-nginx-upload/
- https://www.yanxurui.cc/posts/server/2017-03-21-NGINX-as-a-file-server/
- https://golang.org/pkg/net/http/httputil/
- https://gist.github.com/pinkhominid/e6f53706e0dd8cf34f2bd94c3aa357c5
- https://gist.github.com/mattetti/5914158/f4d1393d83ebedc682a3c8e7bdc6b49670083b84
Previously
Next