-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a new containers
property to the workflow resources
#998
Comments
@JBBianchi @ricardozanini @fjtirado @matthias-pichler What do you guys think? |
If I'm correct, have we discussed this possibility in a meeting or thread? That being said, I give +1 to this proposal. Additionally, we can add that a runtime can have a container definition by default if none is defined. The recommendation is that runtimes make the default versions and architecture clear in their documentation. |
I think I am old guy and I prefer to call an embedded script within the memory adress space of the process running the workflow definition (Im also pragmatical, there are lot of libraries to run embedded javascript and python in most languages) |
@cdavernas so you are proposing that these scripts are also executed on the same container instance? Or just the same image? I am just thinking that if a frequently run workflow that runs a script step in a container, then waits a week and then wants to reuse the same container instance would make it very cumbersome/expensive to keep so many container snapshots around.
@fjtirado how would you in this case prevent a user script from reading restricted env vars or fetching from local IPs? Examples:
I think ultimately the workflow DSL offers a way to describe control (i.e. task) flow as well as data flow. I would abstain from introducing another "out of band" data flow via e.g. files or shared memory. This would severely limit how a runtime could be implemented and make stateless implementations basically impossible. In my opinion tasks should only communicate via input output defined in the DSL. This would allow to make implementations stateless and isolated, which is super important for multi tenant implementations. @cdavernas regarding your initial proposal: I think it would be great to make script & shell calls more deterministic by specifying a container image 👍 I think if we allow reuse, it should be limited to the container image not the container instance. I also see a second benefit: Not only does it allow for consistent versions for e.g. Python but in JavaScript runtimes like node, bun or deno could be specified and thus their internal modules used. Without the |
I was thinking of the container, but you raise a valid point, though it is IMHO rather related to the runtime implementation than to the DSL (how long should containers be "kept" alive and whatnot). Allowing reusing containers, however, enables complex flows that could be performed in a non-sequential way (ex: git clone, do something unrelated such as consuming an event, git checkout without having to restart a whole container and recloning, ...), and would also mitigate the (rightful) concern of @fjtirado concerning performance cost. Maybe we ought to think of additional properties to address your concern? Such as TTL or whatever?
@matthias-pichler I totally agree with you! |
@cdavernas GitHub actions is specifically tailored for CI/CD where repositories need to be checked out and thus a lot of file system access has to happen. They offer to write multi step workflows even offering reusable components. But ultimately all "steps" run on the same (container) instance. Another such example is the Common Workflow Language (aka CWL). It is more targeted towards Life Sciences handling big data: Inputs and Outputs are mostly handled as files and workflows are supposed to run in one long running process. In the middleground there are things like GitLab CI: every "job" (aka "step") runs in it's own container. So the "build" job would run before the "test" job but in completely separate containers and both would need to checkout the repository (yes it is slower than GH Actions). The "build" job would need to specify And then lastly there are more the application level workflow engines, e.g. AWS StepFunctions. Every step is completely stateless and independent from each other. For performance tasks that need the same files would have to be combined into one "longer" running task. Data flow only happens through the input & output of states. |
It is an AWESOME, near perfect comparison indeed. And you are perfectly right: while the idea of reusing a container sounds appealing, it does go against concepts such as atomicity and statelessness. Plus, it would, as you pointed out previously, raise multiple infrastructural concerns. As a matter of consequence, I propose we proceed with "reusable" container configuration (image, env, ...) and forget about "reusable" containers. On a side note, you raise a very interesting point when speaking about
|
On another note: I think we could also utilize document:
dsl: '1.0.0-alpha1'
namespace: default
name: jail-shell-and-script-tasks
version: '0.1.0'
use:
containers:
alpine:
image: alpine:latest
node:
build:
dockerfile: https://github.com/nodejs/docker-node/blob/0c0069246367ac5ac0fc6bca141fb04faaca2f4b/22/bookworm/Dockerfile the content of [ |
@matthias-pichler Thank you for the suggestion, but I have some concerns about the idea, mainly because this property would only be relevant for a local Docker installation. In a remote environment, or on Kubernetes, simply building the image wouldn't be enough — we'd also need to push it to a registry, which would require additional configuration and possibly authentication. |
@cdavernas I do not think running multi platform languages like python or js in embedded mode will break portability as far as we define a compliance level for that script language (meaning that we support embedded scripting only for a particular set of languages, not an arbitrary set) |
The following script will only work on Unix like systems. I someone runs the runtime on a windows machine it will fail even though python is a "portable" language import os
os_info = os.uname() allowing to specify
well we could update the specification to say that the container will no be reused, which is what I am proposing. More concretely we should decide what the behavior of the following is document: {}
do:
- jsWrite:
run:
script:
language: js
code: |
const fs = require('node:fs');
const path = require('node:path');
fs.writeFileSync(path.join(__dirname, 'file.txt'), 'Hello, world!');
- jsRead:
run:
script:
language: js
code: |
const fs = require('node:fs');
const path = require('node:path');
const content = fs.readFileSync(path.join(__dirname, 'file.txt'), 'utf8');
console.log(content);
- pythonRead:
run:
script:
language: python
code: |
with open('file.txt', 'r') as f:
content = f.read()
print(content) do we say:
Option 2 would have far reaching implications for example: document: {}
do:
- jsWrite:
run:
script:
language: js
code: |
const fs = require('node:fs');
const path = require('node:path');
fs.writeFileSync(path.join(__dirname, 'file.txt'), 'Hello, world!');
- delay:
wait:
days: 365
- jsRead:
run:
script:
language: js
code: |
const fs = require('node:fs');
const path = require('node:path');
const content = fs.readFileSync(path.join(__dirname, 'file.txt'), 'utf8');
console.log(content); this would require the runtime to keep (potentially thousands of containers) around for 1 year |
I don't like embedded support because it exposes such a big security problem document: {}
do:
- imds: # gets credentials from the EC2 instance metadata service
run:
script:
language: python
code: |
import requests
response = requests.get("http://169.254.169.254/latest/meta-data/iam/security-credentials/")
- env: # leaks host secrets in a Lambda function
run:
script:
language: js
code: |
console.log(process.env.AWS_SECRET_ACCESS_KEY)
- container: # breaks out of the container
run:
script:
language: python
code: |
import socket
# Connect to the Docker socket
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect("/var/run/docker.sock")
# Send a request to list containers
request = b"{\"method\": \"ContainerList\", \"id\": 1}\n"
sock.sendall(request) |
I think two irreconcialible schools of thought are collisioning here ;) |
Maybe haha. But I think security is job 0 and we should consider this when running author provided code, especially in multi tenant environments. Isolated container instances are one way but I also know of some platforms (e.g Atlassian, Treality, ...) that compiled JS & Python provided by users to WebAssembly which also offers some security boundaries. But even they wrap them in individual Lambda Functions for added security |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
What Would You Like to See Added?
Introduce a new
containers
property to the workflow's resources.Why Is This Needed?
Currently, both
shell
andscript
processes are expected to run within the workflow's environment or platform, which can vary significantly from one runtime to another.For example:
This flexibility is crucial, as we should not impose constraints on any runtime, especially regarding their architectural choices. The diversity in implementations for
shell
andscript
tasks can lead to undesired side effects or even total incompatibility. Consider the following scenarios:One potential solution is to "jail" these tasks by requiring authors to specify a specific environment for each. While this approach is acceptable, it introduces new challenges, such as limiting the ability to run multiple commands or scripts successively within the same container—similar to the capabilities offered by GitHub Actions. Achieving functionality akin to GitHub Actions would necessitate significant and perhaps unnecessary refactoring of the domain-specific language (DSL).
Proposed Solution
I propose allowing authors to define top-level, reusable containers that can be assigned to
script
andshell
tasks. This approach would:Additionally, this proposal would address issue #874 by enabling authors to specify which versions of a script they wish to run, without being restricted to specific ones, as suggested in our weekly discussions.
Example Implementation
The following YAML illustrates the proposed structure:
Conclusion
With this proposal, script and shell tasks would effectively become shorthand for container tasks and could potentially be transformed into cataloged custom functions. This change would lead to a more consistent and flexible approach for executing tasks within workflows.
The text was updated successfully, but these errors were encountered: