Singularity
Singularity Pull
Singularity Registry Server implements a basic version of the Sylabs Library API, meaning that you can pull a container with Singularity directly.
Important you must be using Singularity 3.3.0 or greater for this to work!
If not, you should use Singularity Registry Client
(which also has examples below of using the shub://
endpoint with singularity).
For example, let’s say that I have a collection with a container called collection/container:tag
. and my registry is served at containers.page
. I could pull it as follows:
$ singularity pull --library https://containers.page collection/container:tag
You can also pull a container using Singularity natively with the shub://
uri:
$ singularity pull shub://containers.page/collection/container:tag
Here is an example pull from a local registry:
$ singularity pull --no-https --library http://127.0.0.1 vsoch/dinosaur-collection/another:latest
INFO: Downloading library image
780.0KiB / 780.0KiB [=====================================================================================================================] 100 %0s
WARNING: integrity: signature not found for object group 1
WARNING: Skipping container verification
Note that there was a bug in Singularity that would issue an error with an unexpected 302 - this is at least fixed in 3.10 so upgrade appropriately.
Singularity Push
As of version 1.1.10
, Singularity Registry Server offers a library endpoint
to authenticate and then push containers. First, create an endpoint for your
registry:
$ singularity remote add --no-login DinosaurCloud cloud.dinosaur.io
If you are adding an insecure (e.g., no https) remote:
$ singularity remote add --insecure --no-login DinosaurCloud 127.0.0.1
Verify it’s there:
$ singularity remote list
Cloud Services Endpoints
========================
NAME URI ACTIVE GLOBAL EXCLUSIVE INSECURE
DinosaurCloud 127.0.0.1 NO NO NO YES
SylabsCloud cloud.sylabs.io YES YES NO NO
Keyservers
==========
URI GLOBAL INSECURE ORDER
https://keys.sylabs.io YES NO 1*
* Active cloud services keyserver
The --insecure
flag is going to allow you to develop without https. Otherwise the Singularity client
will require it. Once you add the remote, then you’ll first need to login and get your token at the /token endpoint, for example:
1eb5bc1daeca0f5a215ec242c9690209ca0b3d71
And then provide it (via copy paste) to the Singularity client to create a remote endpoint for your registry:
$ singularity remote login DinosaurCloud
Generate an access token at http://127.0.0.1/auth/tokens, and paste it here.
Token entered will be hidden for security.
Access Token:
INFO: Access Token Verified!
INFO: Token stored in /home/vanessa/.singularity/remote.yaml
If you paste a token that isn’t valid, you’ll get a different message
$ singularity remote login DinosaurCloud
INFO: Authenticating with remote: DinosaurCloud
Generate an API Key at https://127.0.0.1/auth/tokens, and paste here:
API Key:
FATAL: while verifying token: error response from server: Invalid Token
In case you are wondering, the token is kept in plaintext at /home/vanessa/.singularity/remote.yaml
so once you specify to use an endpoint, it knows the token. If you are having
issues copy pasting the token into your terminal (I had some when I wanted to
re-create it) you can also just open up this file and edit the text manually:
$ cat /home/vanessa/.singularity/remote.yaml
Active: SylabsCloud
Remotes:
DinosaurCloud:
URI: 127.0.0.1
Token: 8c5ea955d96570000c72f9609a3afcf60986abf1
System: false
Exclusive: false
Insecure: true
SylabsCloud:
URI: cloud.sylabs.io
System: true
Exclusive: false
The easiest thing to do is now to set your remote to be DinosaurCloud (or whatever
you called it) so you don’t need to specify the push command with --library
:
$ singularity remote use DinosaurCloud
Now that we have a token, let’s try a push! For security purposes, the collection should already exist, and be owned by you. Collaborators are not allowed to push.
# library://user/collection/container[:tag]
$ singularity push -U busybox_latest.sif library://vsoch/dinosaur-collection/another:latest
If you don’t do “remote use” then you can specify the library on the fly:
$ singularity push -U --library http://127.0.0.1 busybox_latest.sif library://vsoch/dinosaur-collection/another:latest
WARNING: Skipping container verifying
INFO: http://127.0.0.1
INFO: 0a4cb168d3dabc3c21a15476be7f4a90396bc2c1
INFO: library://vsoch/dinosaur-collection/another:latest
INFO: [latest]
656.93 KiB / 656.93 KiB [===================================================================] 100.00% 15.36 MiB/s 0s
We use -U
for unsigned.
Push Logic
- If you push an existing tag, if the container is unfrozen, it will be replaced
- If you push an existing tag and the container is frozen (akin to protected) you’ll get permission denied.
- If you push a new tag, it will be added.
- If you push a new image, it will also be added.
- If you push an image to a non existing collection, the collection will be created first, then the image will be added (version
1.1.32
).
Unlike the Sylabs API, when the GET endpoint is made to v1/containers
and the image doesn’t exist,
we return a response for the collection (and not 404). In other words, this response is always returned. We do this because
the Sylabs library client has a strange logic where it doesn’t tag images until after the fact,
and doesn’t send the user’s requested tag to any of the get or creation endpoints. This means
that we are forced on the registry to create a dummy holder tag (that is guaranteed to be unique)
and then to find the container at the end to set tags based on the id of the image
that is created with the upload request. I didn’t see a logical way to create the container using the POST endpoint to
“v1/containers” given that we do not know the tag or version, and would need to know the exact container id
to return later when the container push is requested.
Push Size
The push (as of this version) can now handle large images! Here is the largest that I’ve tested:
$ singularity push -U rustarok_latest.sif library://vsoch/dinosaur-collection/rustarok:latest
WARNING: Skipping container verifying
INFO: http://127.0.0.1
INFO: 0a4cb168d3dabc3c21a15476be7f4a90396bc2c1
INFO: library://vsoch/dinosaur-collection/rustarok:latest
INFO: [latest]
8.09 GiB / 8.09 GiB [====================================================================] 100.00% 91.31 MiB/s 1m30s
Of course, do this at your own risk! That is a CHONKER!
Curl
Like with the Sylabs Library API, it is possible to interact with Singularity Registry Server
using Curl. You can browse the API schema via the /api
path of your server.
Authentication
Authentication is done presenting the token in an Authorization
header:
$ curl -s -H 'Authorization: Bearer <token>' http://127.0.0.1/<api_endpoint>
The token can be found in the navigation in the top right of the registry interface after you log in.
Create a collection
As of version 1.1.32
it is possible to create a new collection via the API. It requires authentication.
First retrieve the numeric id
associated with your username with a GET request to the endpoint /v1/entities/<username>
.
$ curl -s -H 'Authorization: Bearer <token>' /v1/entities/<username>
Here is a response made pretty by piping into json_pp:
{
"data" : {
"collections" : [],
"createdAt" : "2021-02-21T05:20:18.454003Z",
"createdBy" : "",
"customData" : "",
"defaultPrivate" : false,
"deleted" : false,
"deletedAt" : "0001-01-01T00:00:00Z",
"description" : "vsoch",
"id" : "1",
"name" : "vsoch",
"quota" : 0,
"size" : 0,
"updatedAt" : "2021-02-21T05:20:18.479251Z",
"updatedBy" : ""
}
}
Notice that the id is 1? Great! We will use this to create a collection. We next issue
a POST request to the endpoint /v1/collections
and this json payload:
{
"entity": "<user_numeric_id>"
"name": "<new_collection_name>"
"private": true|false
}
Here is an example with our user id of 1:
$ curl -X POST -H 'Authorization: Bearer <token>' -H "Content-Type: application/json" --data '{"entity": 1, "name": "dinosaurs"}' http://127.0.0.1/v1/collections
You can then see the response that the collection was created, and it will appear in the interface:
{
"data" : {
"containers" : [],
"createdAt" : "2021-02-21T05:35:36.491446Z",
"createdBy" : "1",
"customData" : "",
"deleted" : false,
"deletedAt" : "0001-01-01T00:00:00Z",
"description" : "Dinosaurs Collection",
"entity" : "1",
"entityName" : "vsoch",
"id" : "2",
"name" : "dinosaurs",
"owner" : "1",
"private" : false,
"size" : 0,
"updatedAt" : "2021-02-21T05:35:36.505902Z",
"updatedBy" : "1"
}
}
The private
key is optional. If not provided, it defaults to the servers’s configured default for collection creation.
In case of a singularity push
to a non existing collection, the client triggers the collection creation first, using this endpoint, then pushes the image.