|
| 1 | +# Singularity Compose |
| 2 | + |
| 3 | +This is a simple orchestration library for Singularity containers, akin to |
| 4 | +Docker Compose. It is under development, and working for basic examples. |
| 5 | + |
| 6 | +## Who is this intended for? |
| 7 | + |
| 8 | +Singularity compose is intended to run a small number of container instances |
| 9 | +on your host. It is *not* a complicated orchestration tool like Kubernetes, |
| 10 | +but rather a controlled way to represent and manage a set of container instances, |
| 11 | +or services. |
| 12 | + |
| 13 | +## Getting Started |
| 14 | + |
| 15 | +### singularity-compose.yml |
| 16 | + |
| 17 | +For a singularity-compose project, it's expected to have a `singularity-compose.yml` |
| 18 | +in the present working directory. You can look at a simple example here: |
| 19 | + |
| 20 | +```yaml |
| 21 | +version: "1.0" |
| 22 | +instances: |
| 23 | + app: |
| 24 | + build: |
| 25 | + context: ./app |
| 26 | + volumes: |
| 27 | + - ./nginx.conf:/etc/nginx/conf.d/default.conf |
| 28 | + - ./app:/code |
| 29 | + - ./static:/var/www/static |
| 30 | + - ./images:/var/www/images |
| 31 | + ports: |
| 32 | + - 80:80 |
| 33 | +``` |
| 34 | +
|
| 35 | +If you are familiar with [docker-compose](https://docs.docker.com/compose/) |
| 36 | +the file should look very familiar. A key difference is that instead of |
| 37 | +"services" we have "instances." And you guessed correctly - each |
| 38 | +section there corresponds to a |
| 39 | +[Singularity instance](https://sylabs.io/guides/3.2/user-guide/running_services.html) |
| 40 | +that will be created. In this guide, we will walk through each of the sections |
| 41 | +in detail. |
| 42 | +
|
| 43 | +### Instance folders |
| 44 | +
|
| 45 | +Generally, each section in the yaml file corresponds with a container instance to be run, |
| 46 | +and each container instance is matched to a folder in the present working directory. |
| 47 | +For example, if I give instruction to build an `nginx` instance from |
| 48 | +a `nginx/Singularity.nginx` file, I should have the |
| 49 | +following in my singularity-compose: |
| 50 | + |
| 51 | +``` |
| 52 | + nginx: |
| 53 | + build: |
| 54 | + context: ./nginx |
| 55 | + recipe: Singularity.nginx |
| 56 | +``` |
| 57 | + |
| 58 | +The above says that I want to build a container and corresponding instance |
| 59 | +named `nginx`, and use the recipe `Singularity.nginx` in the context |
| 60 | +folder `./nginx` in the present working directory. This gives me the following |
| 61 | +directory structure: |
| 62 | + |
| 63 | +```bash |
| 64 | +singularity-compose-example |
| 65 | +├── nginx |
| 66 | +... |
| 67 | +│ ├── Singularity.nginx |
| 68 | +│ └── uwsgi_params.par |
| 69 | +└── singularity-compose.yml |
| 70 | +
|
| 71 | +``` |
| 72 | + |
| 73 | +Notice how I also have other dependency files for the nginx container |
| 74 | +in that folder. While the context for starting containers with Singularity |
| 75 | +compose is the directory location of the `singularity-compose.yml`, |
| 76 | +the build context for this container is inside the nginx folder. |
| 77 | +We will talk about the [build command](commands.md) soon. First, |
| 78 | +as another option, you can just define a container to pull, |
| 79 | +and it will be pulled to the same folder that is created if it doesn't exist. |
| 80 | + |
| 81 | +``` |
| 82 | + nginx: |
| 83 | + image: docker://nginx |
| 84 | +``` |
| 85 | +
|
| 86 | +This will pull a container `nginx.sif` into a `nginx` context folder: |
| 87 | +
|
| 88 | +```bash |
| 89 | +├── nginx (- created if it doesn't exist |
| 90 | +│ └── nginx.sif (- named according to the instance |
| 91 | +└── singularity-compose.yml |
| 92 | +``` |
| 93 | + |
| 94 | +It's less likely that you will be able to pull a container that is ready to |
| 95 | +go, as typically you will want to customize the |
| 96 | +[startscript](https://sylabs.io/guides/3.2/user-guide/definition_files.html#startscript) |
| 97 | +for the instance. Now that we understand the basic organization, let's |
| 98 | +bring up some instances. |
| 99 | + |
| 100 | +## Quick Start |
| 101 | + |
| 102 | +For this quick start, we are going to use the |
| 103 | +[singularity-compose-simple](https://www.github.com/singularityhub/singularity-compose-simple) |
| 104 | +example. Singularity has a networking issue that currently doesn't allow communication |
| 105 | +between multiple containers (due to iptables and firewall issues) so for now the most we |
| 106 | +can do is show you one container. First, install singularity-compose from pip: |
| 107 | + |
| 108 | +```bash |
| 109 | +$ pip install singularity-compose |
| 110 | +``` |
| 111 | + |
| 112 | +Then, clone the repository: |
| 113 | + |
| 114 | +```bash |
| 115 | +$ git clone https://www.github.com/singularityhub/singularity-compose-simple |
| 116 | +``` |
| 117 | + |
| 118 | +cd inside, and you'll see a `singularity-compose.yml` like we talked about. |
| 119 | + |
| 120 | +```bash |
| 121 | +$ cd singularity-compose-simple |
| 122 | +$ ls |
| 123 | +app images LICENSE nginx.conf README.md singularity-compose.yml static |
| 124 | +``` |
| 125 | + |
| 126 | +Let's take a look at the `singularity-compose.yml` |
| 127 | + |
| 128 | +```yaml |
| 129 | +version: "1.0" |
| 130 | +instances: |
| 131 | + app: |
| 132 | + build: |
| 133 | + context: ./app |
| 134 | + volumes: |
| 135 | + - ./nginx.conf:/etc/nginx/conf.d/default.conf |
| 136 | + - ./app/nginx/uwsgi_params.par:/etc/nginx/uwsgi_params.par |
| 137 | + - ./app/nginx/cache:/var/cache/nginx |
| 138 | + - ./app/nginx/run:/var/run |
| 139 | + - ./app:/code |
| 140 | + - ./static:/var/www/static |
| 141 | + - ./images:/var/www/images |
| 142 | + ports: |
| 143 | + - 80:80 |
| 144 | +... |
| 145 | +``` |
| 146 | + |
| 147 | +It defines a single service, `app`, which has both a Django application and |
| 148 | +a nginx server with the [nginx-upload module](https://www.nginx.com/resources/wiki/modules/upload/) enabled. |
| 149 | +It tells us right away that the folder `app` is the context folder, and inside we can |
| 150 | +see dependency files for nginx and django. |
| 151 | + |
| 152 | +```bash |
| 153 | +$ ls app/ |
| 154 | +manage.py nginx requirements.txt run_uwsgi.sh Singularity upload... |
| 155 | +``` |
| 156 | + |
| 157 | +What we don't see is a container. We need to build that from the Singularity recipe. |
| 158 | +Let's do that. |
| 159 | + |
| 160 | +```bash |
| 161 | +$ singularity-compose build |
| 162 | +``` |
| 163 | + |
| 164 | +Will generate an `app.sif` in the folder: |
| 165 | + |
| 166 | +```bash |
| 167 | +$ ls app/ |
| 168 | +app.sif manage.py nginx requirements.txt run_uwsgi.sh Singularity upload... |
| 169 | +``` |
| 170 | + |
| 171 | +And now we can bring up our instance! |
| 172 | + |
| 173 | +```bash |
| 174 | +$ singularity-compose up |
| 175 | +``` |
| 176 | + |
| 177 | +Verify it's running: |
| 178 | + |
| 179 | +```bash |
| 180 | +$ singularity-compose ps |
| 181 | +INSTANCES NAME PID IMAGE |
| 182 | +1 app 20023 app.sif |
| 183 | +``` |
| 184 | + |
| 185 | +And then look at logs, shell inside, or execute a command. |
| 186 | + |
| 187 | +```bash |
| 188 | +$ singularity-compose logs app |
| 189 | +$ singularity-compose logs app --tail 30 |
| 190 | +$ singularity-compose shell app |
| 191 | +$ singularity-compose exec app uname -a |
| 192 | +``` |
| 193 | + |
| 194 | +When you open your browser to [http://127.0.0.1](http://127.0.0.1) |
| 195 | +you should see the upload interface. |
| 196 | + |
| 197 | + |
| 198 | + |
| 199 | +If you drop a file in the box (or click |
| 200 | +to select) we will use the nginx-upload module to send it directly to the |
| 201 | +server. Cool! |
| 202 | + |
| 203 | + |
| 204 | + |
| 205 | +This is just a simple Django application, the database is sqlite3, and it's |
| 206 | +now appeared in the app folder: |
| 207 | + |
| 208 | +```bash |
| 209 | +$ ls app/ |
| 210 | +app.sif db.sqlite3 manage.py nginx requirements.txt run_uwsgi.sh Singularity upload uwsgi.ini |
| 211 | +``` |
| 212 | + |
| 213 | +The images that you upload are stored in `images` at the root: |
| 214 | + |
| 215 | +```bash |
| 216 | +$ ls images/ |
| 217 | +2018-02-20-172617.jpg 40-acos.png _upload |
| 218 | +``` |
| 219 | + |
| 220 | +And static files are in `static`. |
| 221 | + |
| 222 | +```bash |
| 223 | +$ ls static/ |
| 224 | +admin css js |
| 225 | +``` |
| 226 | + |
| 227 | +Finally, the volumes that we specified in the `singularity-compose.yml` |
| 228 | +tell us exactly where nginx and the application need write. The present |
| 229 | +working directory (where the database is written) is bound to the |
| 230 | +container at `/code`, and nginx dependencies are bound to locations |
| 231 | +in `/etc/nginx`. Notice how the local static and images folder are bound |
| 232 | +to locations in the container where we normally wouldn't have write. |
| 233 | + |
| 234 | +```bash |
| 235 | + volumes: |
| 236 | + - ./nginx.conf:/etc/nginx/conf.d/default.conf |
| 237 | + - ./app/nginx/uwsgi_params.par:/etc/nginx/uwsgi_params.par |
| 238 | + - ./app/nginx/cache:/var/cache/nginx |
| 239 | + - ./app/nginx/run:/var/run |
| 240 | + - ./app:/code |
| 241 | + - ./static:/var/www/static |
| 242 | + - ./images:/var/www/images |
| 243 | +``` |
| 244 | + |
| 245 | +This is likely a prime different between Singularity and Docker compose - Docker doesn't need |
| 246 | +binds for write, but rather to reduce isolation. When you develop an application, |
| 247 | +a lot of your debug will come down to figuring out where the services need to write |
| 248 | +log and similar files, which you might not have been aware of when using Docker. |
| 249 | + |
| 250 | +Continue below to read about networking, and see these commands in detail. |
| 251 | + |
| 252 | +## Networking |
| 253 | + |
| 254 | +When you bring the container up, you'll see generation of an `etc.hosts` file, |
| 255 | +and if you guessed it, this is indeed bound to `/etc/hosts` in the container. |
| 256 | +Let's take a look: |
| 257 | + |
| 258 | +```bash |
| 259 | +10.22.0.2 app |
| 260 | +127.0.0.1 localhost |
| 261 | + |
| 262 | +# The following lines are desirable for IPv6 capable hosts |
| 263 | +::1 ip6-localhost ip6-loopback |
| 264 | +fe00::0 ip6-localnet |
| 265 | +ff00::0 ip6-mcastprefix |
| 266 | +ff02::1 ip6-allnodes |
| 267 | +ff02::2 ip6-allrouters |
| 268 | +``` |
| 269 | + |
| 270 | +This file will give each container that you create (in our case, just one) |
| 271 | +a name on its local network. Singularity by default creates a bridge for |
| 272 | +instance containers, which you can conceptually think of as a router, |
| 273 | +This means that, if I were to reference the hostname "app" in a second container, |
| 274 | +it would resolve to `10.22.0.2`. Singularity compose does this by generating |
| 275 | +these addresses before creating the instances, and then assigning them to it. |
| 276 | +If you would like to see the full commands that are generated, run the up |
| 277 | +with `--debug` (binds and full paths have been removed to make this easier to read). |
| 278 | + |
| 279 | +```bash |
| 280 | +$ singularity instance start \ |
| 281 | + --bind /home/vanessa/Documents/Dropbox/Code/singularity/singularity-compose-simple/etc.hosts:/etc/hosts \ |
| 282 | + --net --network-args "portmap=80:80/tcp" --network-args "IP=10.22.0.2" \ |
| 283 | + --hostname app \ |
| 284 | + --writable-tmpfs app.sif app |
| 285 | +``` |
| 286 | + |
| 287 | +Control and customization of these instances is probably the coolest (and not widely |
| 288 | +used) feature of Singularity. You can create your own network configurations, |
| 289 | +and customie the arguments to the command. Read [here](https://sylabs.io/guides/3.2/user-guide/running_services.html) for more detalis. |
| 290 | + |
| 291 | +## Commands |
| 292 | + |
| 293 | +Read more about the commands shown above [here](commands.md#commands). |
| 294 | + |
| 295 | +## Specification |
| 296 | + |
| 297 | +The [specification](spec) describes in more detail the sections of the singularity-compose.yml. |
| 298 | +For example, in the quick start above, we have a post command for the app instance |
| 299 | +that creates a series of folders on the host. |
| 300 | + |
0 commit comments