Installed apps show up as stacks
Apps that were installed with docker app install show up both as app, and as stack;
docker app ls
INSTALLATION APPLICATION LAST ACTION RESULT CREATED MODIFIED REFERENCE
myinstallation myotherapp (0.1.0) upgrade success 12 minutes 8 minutes
docker stack ls
NAME SERVICES ORCHESTRATOR
myinstallation 1 Swarm
mystack 1 Swarm
Do we want stacks and apps to work in the same "namespace"? Or should we prevent users from interacting with apps through docker stack xxx commands (and vice-versa)?
I guess there's two possible angles;
- apps and stacks are separate things
- apps and stacks form a hierarchy; an app consists of 1 (or perhaps in future more than 1) stacks (and stacks consist of 1 or more services, volumes, etc.)
If 2., then stacks that are part of an app should likely show up under docker stack ls, but we should think how users can/are allows to interact with them.
I think in both cases, we should add additional metadata/labels to (both stacks, and) apps so that we can distinguish apps from stacks, allowing use to filter and/or provide info about the stack/app separate from the local storage in ~/.docker/apps.
Note that adding additional metadata/labels to the deployed apps would also help with https://github.com/docker/app/issues/604
Looking at the information stored (~/.docker/app/installations/37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f/myinstallation.json)
37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688fcould be stored as ID (e.g.com.docker.app.id)myinstallationis the installation name, which is already stored ascom.docker.stack.namespace, but we may want to store that as a "docker app" specific label as well (com.docker.app.name?)
From the myinstallation.json (shown below, collapsed);
{
"name": "myinstallation",
"revision": "01DNS4S9HPYSTS1FCG77WVJCXT",
"created": "2019-09-27T12:34:06.685081+02:00",
"modified": "2019-09-27T12:38:08.950407+02:00",
"bundle": {
"name": "myotherapp",
"version": "0.1.0",
"description": "",
"maintainers": [
{
"name": "sebastiaan",
"email": "[email protected]"
}
],
"invocationImages": [
{
"imageType": "docker",
"image": "myotherapp:0.1.0-invoc"
}
],
"images": {
"hello": {
"imageType": "docker",
"image": "hashicorp/http-echo",
"description": "hashicorp/http-echo"
}
},
"actions": {
"com.docker.app.inspect": {
"stateless": true
},
"com.docker.app.render": {
"stateless": true
},
"com.docker.app.status": {}
},
"parameters": {
"com.docker.app.kubernetes-namespace": {
"type": "string",
"default": "",
"metadata": {
"description": "Namespace in which to deploy"
},
"destination": {
"env": "DOCKER_KUBERNETES_NAMESPACE"
},
"apply-to": [
"install",
"upgrade",
"uninstall",
"com.docker.app.status"
]
},
"com.docker.app.orchestrator": {
"type": "string",
"default": "",
"allowedValues": [
"",
"swarm",
"kubernetes"
],
"metadata": {
"description": "Orchestrator on which to deploy"
},
"destination": {
"env": "DOCKER_STACK_ORCHESTRATOR"
},
"apply-to": [
"install",
"upgrade",
"uninstall",
"com.docker.app.status"
]
},
"com.docker.app.render-format": {
"type": "string",
"default": "yaml",
"allowedValues": [
"yaml",
"json"
],
"metadata": {
"description": "Output format for the render command"
},
"destination": {
"env": "DOCKER_RENDER_FORMAT"
},
"apply-to": [
"com.docker.app.render"
]
},
"com.docker.app.share-registry-creds": {
"type": "bool",
"default": false,
"metadata": {
"description": "Share registry credentials with the invocation image"
},
"destination": {
"env": "DOCKER_SHARE_REGISTRY_CREDS"
}
},
"hello.port": {
"type": "string",
"default": "8080",
"destination": {
"env": "docker_param1"
}
},
"hello.text": {
"type": "string",
"default": "Hello myotherapp!",
"destination": {
"env": "docker_param2"
}
}
},
"credentials": {
"com.docker.app.registry-creds": {
"path": "/cnab/app/registry-creds.json"
},
"docker.context": {
"path": "/cnab/app/context.dockercontext"
}
}
},
"result": {
"message": "",
"action": "upgrade",
"status": "success"
},
"parameters": {
"com.docker.app.kubernetes-namespace": "default",
"com.docker.app.orchestrator": "",
"com.docker.app.render-format": "yaml",
"com.docker.app.share-registry-creds": false,
"hello.port": "8080",
"hello.text": "Hello myapp!"
},
"files": null
}
name(already mentioned above),revision,created,modifiedcould be good candidates for labels (com.docker.app.<property>)
Possibly;
- store standard parameters as labels (
com.docker.app.kubernetes-namespace?) - not sure about the custom parameters, as they may contain sensitive data. If not, they could be stored as
com.docker.app.parameters.<name-of-parameter>
/cc @chris-crone @silvin-lubecki
Hm, actually, looks like the 37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f is not an ID (or at least, the same ID is created when re-deploying the application after removing the local store); is it a hash of the name, not a UUID/random ID?
So, looks like interacting through docker stack is indeed problematic, because docker app currently relies on the local store;
$ docker stack rm myinstallation
Removing service myinstallation_hello
Removing network myinstallation_default
$ docker app ls
INSTALLATION APPLICATION LAST ACTION RESULT CREATED MODIFIED REFERENCE
myinstallation myotherapp (0.1.0) upgrade success 7 minutes About a minute
$ docker app status myinstallation
INSTALLATION
------------
Name: myinstallation
Created: 10 minutes
Modified: 4 minutes
Revision: 01DNS7WG2EJP1Q1KTM1DATP5SD
Last Action: upgrade
Result: SUCCESS
Orchestrator: swarm
APPLICATION
-----------
Name: myotherapp
Version: 0.1.0
Reference:
PARAMETERS
----------
hello.port: 8080
hello.text: Hello myapp!
STATUS
------
@thaJeztah your last result is weird, status should have failed, not being able to reach the rmed stack.
37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f could be stored as ID (e.g. com.docker.app.id)
Actually 37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f is the id of the installation context 😅
The installation store is split by context ids, and inside you will find all the named installations.
Ah! Gotcha 👍 Guess having a GUID stored somewhere would work for IDs
At a high level, I like the idea of 2 where an app consists of one or more stacks. But, I feel that might lead to confusion about apps vs stacks.
I think labeling app-based deployments so that existing stack/service commands can work with them would ease adoption, and make them interoperable with third-party tools like Portainer out of the box.
Perhaps a bigger gain for apps and stacks as a whole would be to create a resource type and APIs for it (as a combined entity). Right now, there is no actual stack resource in the Docker API. The concept of stacks only exist in the Docker CLI. A new resource type could hold the information that's currently being stored locally in ~/.docker/app/installations/, and finally provide an API that external tools can use.