Skip to content

Commit 1f87bf2

Browse files
author
AlexRogalskiy
committed
Added info on workflows
Updates on github-actions
1 parent 819dbb6 commit 1f87bf2

25 files changed

+620
-37
lines changed

Tiltfile

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# -*- mode: Python -*
22

3+
# For more on Extensions, see: https://docs.tilt.dev/extensions.html
4+
load('ext://restart_process', 'docker_build_with_restart')
5+
36
k8s_yaml('kubernetes.yaml')
47
k8s_resource('example-java-patterns', port_forwards=8000, resource_deps=['deploy'])
58

@@ -8,13 +11,16 @@ k8s_resource('example-java-patterns', port_forwards=8000, resource_deps=['deploy
811
# shows you how to set up a custom workflow that measures it.
912
local_resource(
1013
'deploy',
11-
'npm --version > build.txt'
14+
'python3 ./record-start-time.py'
1215
)
1316

1417
# Add a live_update rule to our docker_build
1518
congrats = "🎉 Congrats, you ran a live_update! 🎉"
16-
docker_build('java-patterns', '.', build_args={'IMAGE_SOURCE': 'node', 'IMAGE_TAG': '12-buster'},
19+
docker_build_with_restart('java-patterns', '.', build_args={'IMAGE_SOURCE': 'node', 'IMAGE_TAG': '12-buster'},
20+
dockerfile='./Dockerfile',
21+
entrypoint=['mkdocs', 'serve', '--verbose', '--dirtyreload'],
1722
live_update=[
1823
sync('.', '/usr/src/app'),
24+
run('python3 ./record-start-time.py'),
1925
run('cd /usr/src/app/docs && pip3.8 install -r requirements.txt --quiet', trigger='./requirements.txt')
2026
])

build.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
7.18.1
1+
startTimeSecs = 1626901134;
2+
startTimeNanos = 979205369;

docs/patterns/snippet-template.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
| Name | Category | Description | Labels | Links |
2+
| ----------------- | :-------------------: | :-----------------: | :---------------------: | :-------: |
3+
| Snippet name | Snippet category | Snippet description | 'utility','intermediate'| <links> |
4+
5+
# Snippet Template
6+
7+
Explain briefly what the snippet does.
8+
9+
- Explain briefly how the snippet works.
10+
- Use bullet points for your snippet's explanation.
11+
- Try to explain everything briefly but clearly.
12+
13+
## Snippet samples
14+
15+
```java
16+
public interface Snippet {
17+
// snippets declaration
18+
}
19+
```
20+
21+
```java
22+
public class BaseSnippet implements Snippet {
23+
// snippets implementation
24+
}
25+
```

docs/patterns/snippet.template.md

-21
This file was deleted.

docs/reporting/bug_report.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
***
2-
3-
## Name: Bug report&#xD;&#xA;about: Create a report to help us improve&#xD;&#xA;title: ''&#xD;&#xA;labels: ''&#xD;&#xA;assignees: ''
1+
| Name | Category | Description | Labels | Links |
2+
| ----------------- | :-------------------: | :-----------------: | :---------------------: | :-------: |
3+
| Bug name | Bug category | Bug description | 'utility','intermediate'| <links> |
44

55
# Bug Report
66

docs/reporting/custom_report.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
***
2-
3-
## Name: Custom issue template&#xD;&#xA;about: Describe this issue template's purpose here.&#xD;&#xA;steps: ''&#xD;&#xA;labels: ''&#xD;&#xA;assignees: ''
1+
| Name | Category | Description | Labels | Links |
2+
| ----------------- | :-------------------: | :-----------------: | :---------------------: | :-------: |
3+
| Report name | Report category | Report description | 'utility','intermediate'| <links> |
44

55
# Custom Report
66

docs/reporting/feature_request_template.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
***
2-
3-
## Name: Feature request&#xD;&#xA;about: Suggest an idea for this project&#xD;&#xA;title: ''&#xD;&#xA;labels: ''&#xD;&#xA;assignees: ''
1+
| Name | Category | Description | Labels | Links |
2+
| ----------------- | :-------------------: | :-----------------: | :---------------------: | :-------: |
3+
| Feature name | Feature category | Feature description | 'utility','intermediate'| <links> |
44

55
# Feature Request Template
66

docs/reporting/issue_template.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
***
2-
3-
## Name: Issue report&#xD;&#xA;about: Create an issue report&#xD;&#xA;title: ''&#xD;&#xA;labels: ''&#xD;&#xA;assignees: ''
1+
| Name | Category | Description | Labels | Links |
2+
| ----------------- | :-------------------: | :-----------------: | :---------------------: | :-------: |
3+
| Issue name | Issue category | Issue description | 'utility','intermediate'| <links> |
44

55
# Issue Report
66

@@ -17,7 +17,7 @@
1717
- **Tool/Service/Component**: \[name, version] for example "PIT 1.2.0, Descartes 0.2-SNAPSHOT, PITMP 1.0.1""
1818
- **Execution Environment**: \[platform, OS, etc] Description of the execution environment, e.g "Linux
1919
OpenSuse Tumbleweed" or "Linux Ubuntu 16.04.1" including information about the version of the executed
20-
STAMP tools/services and their local dependencies (in case of standalone execution)
20+
STAMP tools/services, and their local dependencies (in case of standalone execution)
2121
- **Reporter**: \[name, mail] Reference information of the reporter, so the assignee can contact back for
2222
further issue refinement, if needed.
2323

record-start-time.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import re
2+
import time
3+
4+
filename = "build.txt"
5+
f = open(filename, "r")
6+
contents = f.read()
7+
f.close()
8+
9+
timestamp_sec = int(time.time())
10+
timestamp_nano = (float(time.time()) - timestamp_sec) * 1000 * 1000 * 1000
11+
contents = re.sub(r'startTimeSecs = .*;',
12+
"startTimeSecs = %d;" % timestamp_sec,
13+
contents)
14+
contents = re.sub(r'startTimeNanos = .*;',
15+
"startTimeNanos = %d;" % timestamp_nano,
16+
contents)
17+
18+
f = open(filename, "w")
19+
f.write(contents)
20+
f.close()

record-start-time.sh

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
tmpfile=$(mktemp /tmp/tilt-example-java.XXXXXX)
6+
7+
cat build.txt |
8+
sed -e "s/startTimeSecs = .*;/startTimeSecs = $(date +%-s);/" |
9+
sed -e "s/startTimeNanos = .*;/startTimeNanos = $(date +%-N);/" >$tmpfile
10+
11+
mv $tmpfile build.txt

tilt_modules/extensions.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Extensions": [
3+
{
4+
"Name": "restart_process",
5+
"ExtensionRegistry": "https://github.com/tilt-dev/tilt-extensions",
6+
"TimeFetched": "2021-07-21T23:51:31.73649+03:00"
7+
}
8+
]
9+
}
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tilt-restart-wrapper
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
FROM alpine/git
2+
3+
RUN apk update && apk add make
4+
RUN apk add build-base
5+
6+
RUN git clone https://github.com/eradman/entr.git /entr
7+
WORKDIR /entr
8+
RUN git checkout c564e6bdca1dfe2177d1224363cad734158863ad
9+
RUN ./configure; CFLAGS="-static" make install
10+
11+
FROM scratch
12+
13+
COPY --from=0 /usr/local/bin/entr /
14+
15+
ADD tilt-restart-wrapper /
+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# Restart Process
2+
3+
This extension helps create images that can restart on `live_update`:
4+
5+
- `docker_build_with_restart`: wraps a `docker_build` call
6+
- `custom_build_with_restart`: wraps a `custom_build` call
7+
8+
At the end of a `live_update`, the container's process will rerun itself.
9+
10+
(Use it in place of the `restart_container()` Live Update step, which has been deprecated for Kubernetes resources.)
11+
12+
## When to Use
13+
Use this extension when you have an image and you want to re-execute its entrypoint/command as part of a `live_update`.
14+
15+
E.g. if your app is a static binary, you'll probably need to re-execute the binary for any changes you made to take effect.
16+
17+
(If your app has hot reloading capabilities--i.e. it can detect and incorporate changes to its source code without needing to restart--you probably don't need this extension.)
18+
19+
### Unsupported Cases
20+
This extension does NOT support process restarts for:
21+
- Images built with `custom_build` using any of the `skips_local_docker`, `disable_push`, or `tag` parameters.
22+
- Images run in Docker Compose resources (use the [`restart_container()`](https://docs.tilt.dev/api.html#api.restart_container) builtin instead)
23+
- Images without a shell (e.g. `scratch`, `distroless`)
24+
- Container commands specified as `command` in Kubernetes YAML will be overridden by this extension.
25+
- However, the `args` field is still available; [reach out](https://tilt.dev/contact) if you need help navigating the interplay between Tilt and these YAML values
26+
- CRDs
27+
28+
If this extension doesn't work for your use case, [see our docs for alternatives](https://docs.tilt.dev/live_update_reference.html#restarting-your-process).
29+
30+
Run into a bug? Need a use case that we don't yet support? Let us know--[open an issue](https://github.com/tilt-dev/tilt-extensions/issues) or [contact us](https://tilt.dev/contact).
31+
32+
## How to Use
33+
34+
Import this extension by putting the following at the top of your Tiltfile:
35+
```python
36+
load('ext://restart_process', 'docker_build_with_restart')
37+
```
38+
39+
For the image that needs the process restart, replace your existing `docker_build` call:
40+
```python
41+
docker_build(
42+
'foo-image',
43+
'./foo',
44+
arg1=val1,
45+
arg2=val2,
46+
live_update=[x, y, z...]
47+
)
48+
```
49+
with a `docker_build_with_restart` call:
50+
```python
51+
docker_build_with_restart(
52+
'foo-image',
53+
'./foo',
54+
entrypoint='/go/bin/foo',
55+
arg1=val1,
56+
arg2=val2,
57+
live_update=[x, y, z...]
58+
)
59+
```
60+
The call above looks just like the initial `docker_build` call except for one added parameter, `entrypoint` (in this example, `/go/bin/foo`). This is the command that you want to run on container start and _re-run_ on Live Update.
61+
62+
A custom_build call looks similar:
63+
64+
```python
65+
load('ext://restart_process', 'custom_build_with_restart')
66+
67+
custom_build_with_restart(
68+
'foo-image',
69+
'docker build -t $EXPECTED_REF ./foo',
70+
deps=['./foo'],
71+
live_update=[sync(...)]
72+
)
73+
```
74+
75+
### Troubleshooting
76+
#### `failed running [touch /tmp/.restart-proc']`
77+
If you see an error of the form:
78+
```
79+
ERROR: Build Failed: ImageBuild: executor failed running [touch /tmp/.restart-proc']: exit code: 1
80+
```
81+
this often means that your Dockerfile user ([see docs](https://docs.docker.com/engine/reference/builder/#user)) doesn't have permission to write to the file we use to signal a process restart. Use the `restart_file` parameter to specify a file that your Dockerfile user definitely has write access to.
82+
83+
### API
84+
```python
85+
def docker_build_with_restart(ref: str, context: str,
86+
entrypoint: Union[str, List[str]],
87+
live_update: List[LiveUpdateStep],
88+
base_suffix: str = '-base',
89+
restart_file: str = '/.restart-proc',
90+
trigger: Union[str, List[str]] = [],
91+
**kwargs
92+
):
93+
"""Args:
94+
ref: name for this image (e.g. 'myproj/backend' or 'myregistry/myproj/backend'); as the parameter of the same name in docker_build
95+
context: path to use as the Docker build context; as the parameter of the same name in docker_build
96+
entrypoint: the command to be (re-)executed when the container starts or when a live_update is run
97+
live_update: set of steps for updating a running container; as the parameter of the same name in docker_build
98+
base_suffix: suffix for naming the base image, applied as {ref}{base_suffix}
99+
restart_file: file that Tilt will update during a live_update to signal the entrypoint to rerun
100+
trigger: (optional) list of local paths. If specified, the process will ONLY be restarted when there are changes
101+
to the given file(s); as the parameter of the same name in the LiveUpdate `run` step.
102+
**kwargs: will be passed to the underlying `docker_build` call
103+
"""
104+
105+
106+
def custom_build_with_restart(ref: str, command: str, deps: List[str], entrypoint,
107+
108+
entrypoint: Union[str, List[str]],
109+
live_update: List[LiveUpdateStep],
110+
base_suffix: str = '-base',
111+
restart_file: str = '/.restart-proc',
112+
trigger: Union[str, List[str]] = [],
113+
, **kwargs
114+
):
115+
"""
116+
Args:
117+
ref: name for this image (e.g. 'myproj/backend' or 'myregistry/myproj/backend'); as the parameter of the same name in custom_build
118+
command: build command for building your image
119+
deps: source dependencies of the custom build
120+
entrypoint: the command to be (re-)executed when the container starts or when a live_update is run
121+
live_update: set of steps for updating a running container; as the parameter of the same name in custom_build
122+
base_suffix: suffix for naming the base image, applied as {ref}{base_suffix}
123+
restart_file: file that Tilt will update during a live_update to signal the entrypoint to rerun
124+
trigger: (optional) list of local paths. If specified, the process will ONLY be restarted when there are changes
125+
to the given file(s); as the parameter of the same name in the LiveUpdate `run` step.
126+
**kwargs: will be passed to the underlying `custom_build` call
127+
"""
128+
```
129+
130+
## What's Happening Under the Hood
131+
*If you're a casual user/just want to get your app running, you can stop reading now. However, if you want to dig deep and know exactly what's going on, or are trying to debug weird behavior, read on.*
132+
133+
This extension wraps commands in `tilt-restart-wrapper`, which makes use of [`entr`](https://github.com/eradman/entr/)
134+
to run arbitrary commands whenever a specified file changes. Specifically, we override the container's entrypoint with the following:
135+
136+
```
137+
/tilt-restart-wrapper --watch_file='/.restart-proc' <entrypoint>
138+
```
139+
140+
This invocation says:
141+
- when the container starts, run <entrypoint>
142+
- whenever the `/.restart-proc` file changes, re-execute <entrypoint>
143+
144+
We also set the following as the last `live_update` step:
145+
```python
146+
run('date > /.restart-proc')
147+
```
148+
149+
Because `tilt-restart-wrapper` will re-execute the entrypoint whenever `/.restart-proc'` changes, the above `run` step will cause the entrypoint to re-run.
150+
151+
#### Provide `tilt-restart-wrapper`
152+
For this all to work, the `entr` binary must be available on the Docker image. The easiest solution would be to call e.g. `apt-get install entr` in the Dockerfile, but different base images will have different package managers; rather than grapple with that, we've made a statically linked binary available on Docker image: [`tiltdev/entr`](https://hub.docker.com/repository/docker/tiltdev/entr).
153+
154+
To build `image-foo`, this extension will:
155+
- build your image as normal (via `docker_build`, with all of your specified args/kwargs) but with the name `image-foo-base`
156+
- build `image-foo` (the actual image that will be used in your resource) as a _child_ of `image-foo-base`, with the `tilt-process-wrapper` and its dependencies available
157+
158+
Thus, the final image produced is tagged `image-foo` and has all the properties of your original `docker_build`, plus access to the `tilt-restart-wrapper` binary.
159+
160+
#### Why a Wrapper?
161+
Why bother with `tilt-restart-wrapper` rather than just calling `entr` directly?
162+
163+
Because in its canonical invocation, `entr` requires that the file(s) to watch be piped via stdin, i.e. it is invoked like:
164+
```
165+
echo "/.restart-proc" | entr -rz /bin/my-app
166+
```
167+
168+
When specified as a `command` in Kubernetes or Docker Compose YAML (this is how Tilt overrides entrypoints), the above would therefore need to be executed as shell:
169+
```
170+
/bin/sh -c 'echo "/.restart-proc" | entr -rz /bin/my-app'
171+
```
172+
Any `args` specified in Kubernetes/Docker Compose are attached to the end of this call, and therefore in this case would apply TO THE `/bin/sh -c` CALL, rather than to the actual command run by `entr`; that is, any `args` specified by the user would be effectively ignored.
173+
174+
In order to make `entr` usable without a shell, this extension uses [a simple binary](/restart_process/tilt-restart-wrapper.go) that invokes `entr` and writes to its stdin.
175+
176+
Note: ideally `entr` could accept files-to-watch via flag instead of stdin, but (for a number of good reasons) this feature isn't likely to be added any time soon (see [entr#33](https://github.com/eradman/entr/issues/33)).
177+
178+
## For Maintainers: Releasing
179+
If you have push access to the `tiltdev` repository on DockerHub, you can release a new version of the binaries used by this extension like so:
180+
1. run `release.sh` (builds `tilt-restart-wrapper` from source, builds and pushes a Docker image with the new binary and a fresh binary of `entr` also installed from source)
181+
2. update the image tag in the [Tiltfile](/restart_process/Tiltfile) with the tag you just pushed (you'll find the image referenced in the Dockerfile contents of the child image--look for "FROM tiltdev/restart-helper")

0 commit comments

Comments
 (0)