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!
Singularity Registry Client
Singularity Registry Global Client, or sregistry-cli, is a general client to interact with Singularity images at remote endpoints, and it provides such an endpoint for Singularity Registry Server. We will provide basic instructions here, and for the full documentation, please see the getting started guide here. Note that you will need to export your credentials in order to have authenticated interaction with sregistry.
Install
sregistry Installation
sregistry
is the client for Singularity Registry server. To install, you can do the following:
git clone https://github.com/singularityhub/sregistry-cli
cd sregistry-cli
python setup.py install
To check your install, run this command to make sure the sregistry
client is found.
which sregistry
Container Install
We have provided a Singularity build definition for you, for which you can use to build a container that serves as the sregistry client (and this will likely be provided on Singularity Hub so you don’t even need to do that.) To build, do the following:
cd sregistry/
# Singularity 2.4 and up
sudo singularity build sregistry Singularity
# For Singularity earlier than 2.4 (deprecated)
singularity create --size 2000 sregistry
sudo singularity bootstrap sregistry Singularity
If you install via this option, you will want to make sure the container itself is somewhere on your path, with appropriate permissions for who you want to be able to use it.
Commands
This brief tutorial assumes that you have Singularity installed.
Pull
Not shown in the demo above is the pull command, but it does the same thing as the singularity pull.
sregistry pull banana/pudding:milkshake
Progress |===================================| 100.0%
Success! banana-pudding-milkshake.img
This is useful so that you can (locally from your registry) pull an image without needing to specify the registry url. It’s also important because registry support will only be added to Singularity when the entire suite of compoenents are ready to go!
Push
If you don’t have an image handy, you can pull one:
singularity pull docker://busybox
And then a push to your registry looks like this:
$ sregistry push -U busybox_latest.sif --name dinosaur/avocado --tag delicious
$ sregistry push -U busybox_latest.sif --name meowmeow/avocado --tag nomnomnom
$ sregistry push -U busybox_latest.sif --name dinosaur/avocado --tag whatinthe
If you don’t specify a tag, latest
is used. If you have authentication issues,
remember that you need to export a token for your user, and ensure that the user is either an admin/manager, or
that you have set the USER_COLLECTIONS
variable to true. You can read more about roles here, and more about teams to manage groups of people.
List
List is a general command that will show a specific container, a specific collection, optionally with a tag. Examples are provided below:
# All collections
sregistry list
# A particular collection
sregistry list dinosaur
# A particular container name across collections
sregistry list /avocado
# A named container, no tag
sregistry list dinosaur/avocado
# A named container, with tag
sregistry list dinosaur/avocado:delicious
In addition to listing containers, sregistry
can show you metadata! It does this by issuing an inspect command at upload time, so that no processing is needed on the server side. Singularity Registry is a Dockerized application, so it would require –privileged mode, which is a bad idea. Anyway, we can look at environment (--env/-e
), runscript (--runscript/-r
), tests (--test/-t
), or Singularity
definition recipe (--deffile/-d
):
# Show me environment
sregistry list dinosaur/tacos:delicious --env
# Add runscript
sregistry list dinosaur/tacos:delicious --e --r
# Definition recipe (Singularity) and test
sregistry list dinosaur/tacos:delicious --d --t
# All of them
sregistry list dinosaur/tacos:delicious --e --r --d --t
Delete
Delete requires the same authentication as push, and you will need to confirm with yes/no
sregistry delete dinosaur/tacos:delicious
sregistry list
if you want to force it, add --force
sregistry delete dinosaur/tacos:delicious --force
Labels
Labels are important, and so they are represented as objects in the database for index, query, etc. Akin to containers, we can list and search:
# All labels
sregistry labels
# A specific key
sregistry labels --key maintainer
# A specific value
sregistry labels --value vanessasaur
# A specific key and value
sregistry labels --key maintainer --value vanessasaur
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.