Skip to content
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

DOCS-2930: Add first_run flow for Docker modules #4187

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion docs/operate/reference/advanced-modules/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ tags:
"components",
"services",
]
description: "Some usage may require you to define new APIs or deploy custom components using a server on a remote part"
description: "Some usage may require you to define new APIs or deploy custom components in non-standard ways."
aliases:
- /program/extend/
- /modular-resources/advanced/
Expand Down Expand Up @@ -46,6 +46,65 @@ Running {{< glossary_tooltip term_id="modular-resource" text="modular resources"

However, if you are unable to use modular resources because you need to host `viam-server` on a non-Linux system or have an issue with compilation, you may need to [implement a custom component and register it on a server configured as a remote](/operate/reference/advanced-modules/custom-components-remotes/) on your machine.

## Package and deploy using Docker

In rare cases, you may need to package and deploy a module using Docker.
Use cases for this include:

- Your module has complex system dependencies that cannot be easily installed on a machine.
- You use a large container image and some layers are already used by your machine which means layer caching can reduce the size of the download.
- You have specific security requirements that are difficult to meet with the default module deployment.

If you choose to deploy your module using Docker, we recommend creating a "first run" script or binary to run any necessary setup steps.
Note this is _not_ recommended for modules that do not use Docker, it adds unnecessary complexity.

{{% expand "Click for first run script instructions" %}}

1. Create a tarball that contains:

- The module's entrypoint script or binary
- A <file>meta.json</file>
- A first run script or binary that will be executed during the setup phase, for example:

```sh {id="terminal-prompt" class="command-line" data-prompt="$"}
#!/usr/bin/env bash

docker pull mongo:6
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this pulls the image but then how does the container get run? I think we probably want to link to an example of that. Also

And should this run with https://github.com/viam-soleng/viam-docker-manager or is this entirely separate?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this example is right: in first_run.sh, you pull the image, and then in your module's main executable, you run the image, and that second part should be obvious for anyone developing with docker. We could add in such an example, but it's trivial:

#!/bin/bash
set -euxo pipefail
# This example module runs inside the docker image you should have downloaded in first_run.sh
SOCKET_DIR=`dirname $1`
VIAM_DIR=`realpath ~/.viam`
exec docker run \
     --rm \
     --runtime=nvidia --gpus=all \
     -v /etc/passwd:/etc/passwd \
     -v /etc/group:/etc/group \
     -v $SOCKET_DIR:$SOCKET_DIR \
     -v $VIAM_DIR:$VIAM_DIR \
     ghcr.io/viam-modules/viam-mlmodelservice-triton/jetpack6:0.9.0 \
     LD_PRELOAD=libjemalloc.so.2 VIAM_MODULE_DATA="$VIAM_MODULE_DATA" /opt/viam/bin/viam_mlmodelservice_triton "$@" 2>&1

Copy link
Member

@penguinland penguinland Apr 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(that example is from the Triton module, and although there are lots of options specified for the docker line, anyone developing with docker should know which ones they need to set.)

It's really just

#!/bin/bash
exec docker run <whatever-the-module-author-intended-to-put-here>

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's probably clear to someone who would immediately know that there's an executable that gets called and where to edit it. I don't think it'll hurt us to add this two liner and where to put it here as the entry point script. @JessamyT you can use the https://hub.docker.com/_/hello-world image to test that this works


cat << EOF
-------------------------------------
The setup script ran successfully!
-------------------------------------
EOF

exit 0
```

[This example Makefile on GitHub](https://github.com/viam-labs/wifi-sensor/blob/7823b6ad3edcbbbf20b06c34b3181453f5f3f078/Makefile) builds a module binary and bundles it along with a <file>meta.json</file> and first run script.<br><br>

1. Edit the <file>meta.json</file> to include a `first_run` field that points to the first run script or binary.

```json
{
...
"first_run": "first_run.sh"
}
```

1. Configure your module on your machine in the same way as you would for a regular module.
The first run script will execute once when `viam-server` receives a new configuration.
It will only execute once per module or per version of the module.

1. (Optional) After a first run script runs successfully, Viam adds a marker file with a `.first_run_succeeded` suffix in the module’s data directory on disk.
It has the location and form: `/root/.viam/packages/data/module/<MODULE_ID>-<VERSION>-<ARCH>.first_run_succeeded`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect there should be a slash before .first_run_succeeded, but haven't checked on that personally. Maybe it's correct as-is.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm also from Maxim's guide--not sure if there's a reasonably practical way to check for sure

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😳 I went to one of my machines with a module with a first_run script to check, and got surprised that instead of having such a file anywhere, I have a meta.json does not exist, skipping first run message scattered throughout my logs! I can't help, and I've got some modules to go fix.

Thanks for pointing me towards this bug!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eep! I don't have any Docker modules to test this on... @cheukt since it looks like you've been maintaining the confluence instructions, can you confirm?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is unpackedModDir + FirstRunSuccessSuffix, an example would be .viam/packages/data/module/e76d1b3b-0468-4efd-bb7f-fb1d2b352fcb-viamrtsp-0_1_0-linux-amd64/bin.first_run_succeeded
https://github.com/viamrobotics/rdk/blob/1af4d812c36e43c2f08b847290e1642489eb1df8/config/module.go#L279

If you want to force a first run script to run again without changing the configured module or module version, you can do so by deleting this file.

1. (Optional) By default, a first run script will timeout after 1 hour.
This can be adjusted by adding a `first_run_timeout` to the module’s configuration.
For example, `"first_run_timeout": "5m"` will lower the script timeout to 5 minutes.

{{% /expand %}}

## Design a custom ML model

When working with the [ML model service](/dev/reference/apis/services/ml/), you can deploy an [existing model](/data-ai/ai/deploy/) or [train your own model](/data-ai/ai/train/).
Expand Down
Loading