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

Document launch process #188

Merged
merged 7 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
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
139 changes: 139 additions & 0 deletions content/docs/app-developer-guide/run-an-app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
+++
title="Specify launch process"
weight=1
summary="Learn how to specify the launch process for an app."
+++

### Build a multi-process app

For this example we will use the `hello-processes` buildpack from our [samples][samples] repo.

```bash
# clone the repo
git clone https://github.com/buildpacks/samples

# build the app
pack build multi-process-app \
--builder cnbs/sample-builder:alpine \
--buildpack samples/java-maven \
--buildpack samples/buildpacks/hello-processes/ \
--path samples/apps/java-maven/
```

If you inspect the app image with `pack`, you will see multiple process types defined:

```bash
pack inspect-image multi-process-app
```

The output should look similar to the below:

```bash
Inspecting image: multi-process-app

REMOTE:
(not present)

LOCAL:

Stack: io.buildpacks.samples.stacks.alpine

Base Image:
Reference: f5898fb2b30c2b66f5a69a424bae6473259fa48b387df35335f04332af7f1091
Top Layer: sha256:700c764e7c5d5c75e6a0fc7d272b7e1c70ab327c03fbdf4abd9313e5ec3217f7

Run Images:
cnbs/sample-stack-run:alpine

Buildpacks:
ID VERSION
samples/java-maven 0.0.1
samples/hello-processes 0.0.1

Processes:
TYPE SHELL COMMAND ARGS
web (default) bash java -jar target/sample-0.0.1-SNAPSHOT.jar
sys-info bash /layers/samples_hello-processes/sys-info/sys-info.sh
```

Notice that the default process type is `web`. This is because `pack` will always attempt to set the default process type to `web` unless the `--default-process` flag is passed.
If we had run the `pack build` command above with `--default-process sys-info`, `sys-info` would be the default process for the app image!

### Run a multi-process app

Buildpacks are designed to give you much flexibility in how you run your app. The lifecycle includes a binary called the `launcher` which is present in the final app image and is responsible for starting your app.
By default, the `launcher` will start processes with `bash` (these are referred to as `non-direct` processes). Processes that are started without `bash` are referred to as `direct` processes.
The `launcher` will source any profile scripts (for `non-direct` processes) and set buildpack-provided environment variables in the app's execution environment before starting the app process.

#### Default process type

If you would like to run the default process, you can simply run the app image without any additional arguments:

```bash
docker run --rm -p 8080:8080 multi-process-app
```

#### Default process type with additional arguments

If you would like to pass additional arguments to the default process, you can run the app image with the arguments specified in the command:

```bash
docker run --rm -p 8080:8080 multi-process-app --spring.profiles.active=mysql
```

#### Non-default process-type

To run a non-default process type, set the process type as the entrypoint for the run container:

```bash
docker run --rm --entrypoint sys-info multi-process-app
```

#### Non-default process-type with additional arguments

You can pass additional arguments to a non-default process type:

```bash
docker run --rm --entrypoint sys-info multi-process-app --spring.profiles.active=mysql
```

#### User-provided shell process

You can even override the buildpack-defined process types:

```bash
docker run --rm --entrypoint launcher -it multi-process-app bash
docker run --rm --entrypoint launcher -it multi-process-app echo hello "$WORLD" # $WORLD is evaluated on the host machine
docker run --rm --entrypoint launcher -it multi-process-app echo hello '$WORLD' # $WORLD is evaluated in the container after profile scripts are sourced
```

#### User-provided shell process with bash script

An entire script may be provided as a single argument:

```bash
docker run --rm --entrypoint launcher -it multi-process-app 'for opt in $JAVA_OPTS; do echo $opt; done'
```

#### User-provided direct process

By passing `--` before the command, we instruct the `launcher` to start the provided process without `bash`.
Note that while buildpack-provided environment variables will be set in the execution environment, no profile scripts will be sourced (as these require `bash`):

```bash
docker run --rm --entrypoint launcher multi-process-app -- env # output will include buildpack-provided env vars
docker run --rm --entrypoint launcher multi-process-app -- echo hello "$WORLD" # $WORLD is evaluated on the host machine
docker run --rm --entrypoint launcher multi-process-app -- echo hello '$WORLD' # $WORLD is not evaluated, output will include string literal `$WORLD`
```

#### No launcher

You can bypass the launcher entirely by setting a new entrypoint for the run container:

```bash
docker run --rm --entrypoint bash -it multi-process-app # profile scripts have NOT been sourced and buildpack-provided env vars are NOT set in this shell
```

To learn more about the launcher, see the [platform spec](https://github.com/buildpacks/spec/blob/main/platform.md#launcher).

[samples]: https://github.com/buildpacks/samples
natalieparellano marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This is a step-by-step tutorial for creating a Ruby Cloud Native Buildpack.
- [Detecting your application](/docs/buildpack-author-guide/create-buildpack/detection)
- [Building your application](/docs/buildpack-author-guide/create-buildpack/build-app)
- [Making your application runnable](/docs/buildpack-author-guide/create-buildpack/make-app-runnable)
- [Specifying multiple process types](/docs/buildpack-author-guide/create-buildpack/specify-multiple-process-types)
jromero marked this conversation as resolved.
Show resolved Hide resolved
- [Improving performance with caching](/docs/buildpack-author-guide/create-buildpack/caching)
- [Making your buildpack configurable](/docs/buildpack-author-guide/create-buildpack/make-buildpack-configurable)

Expand Down
24 changes: 21 additions & 3 deletions content/docs/buildpack-author-guide/create-buildpack/caching.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
+++
title="Improving performance with caching"
weight=406
weight=407
creatordisplayname = "Scott Sisil"
creatoremail = "[email protected]"
lastmodifierdisplayname = "Javier Romero"
Expand Down Expand Up @@ -66,7 +66,16 @@ echo -e 'cache = true\nlaunch = true' > "$bundlerlayer.toml"
bundle install --path "$bundlerlayer" --binstubs "$bundlerlayer/bin"

# 7. SET DEFAULT START COMMAND
echo 'processes = [{ type = "web", command = "bundle exec ruby app.rb"}]' > "$layersdir/launch.toml"
cat > "$layersdir/launch.toml" <<EOL
[[processes]]
type = "web"
command = "bundle exec ruby app.rb"
EOL
cat >> "$layersdir/launch.toml" <<EOL
[[processes]]
type = "worker"
command = "bundle exec ruby worker.rb"
EOL
```

Now when we run:
Expand Down Expand Up @@ -210,7 +219,16 @@ else
fi

# 7. SET DEFAULT START COMMAND
echo 'processes = [{ type = "web", command = "bundle exec ruby app.rb"}]' > "$layersdir/launch.toml"
cat > "$layersdir/launch.toml" <<EOL
[[processes]]
type = "web"
command = "bundle exec ruby app.rb"
EOL
cat >> "$layersdir/launch.toml" <<EOL
[[processes]]
type = "worker"
command = "bundle exec ruby worker.rb"
EOL
```

Now when you build your app:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ To make your app runnable, we need to set a default start command. Add the follo

```bash
# Set default start command
echo 'processes = [{ type = "web", command = "bundle exec ruby app.rb"}]' > "$layersdir/launch.toml"
cat > "$layersdir/launch.toml" <<EOL
[[processes]]
type = "web"
command = "bundle exec ruby app.rb"
EOL
```

Your full `build` script should now look like the following:
Expand Down Expand Up @@ -49,7 +53,11 @@ bundle install

# ========== ADDED ===========
# 7. SET DEFAULT START COMMAND
echo 'processes = [{ type = "web", command = "bundle exec ruby app.rb"}]' > "$layersdir/launch.toml"
cat > "$layersdir/launch.toml" <<EOL
[[processes]]
type = "web"
command = "bundle exec ruby app.rb"
EOL
```

Then rebuild your app using the updated buildpack:
Expand Down Expand Up @@ -77,4 +85,4 @@ Test it out by navigating to [localhost:8080](http://localhost:8080) in your fav

---

<a href="/docs/buildpack-author-guide/create-buildpack/caching" class="button bg-pink">Next Step</a>
<a href="/docs/buildpack-author-guide/create-buildpack/specify-multiple-process-types" class="button bg-pink">Next Step</a>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
+++
title="Making your buildpack configurable"
weight=407
weight=408
creatordisplayname = "Scott Sisil"
creatoremail = "[email protected]"
lastmodifierdisplayname = "Javier Romero"
Expand Down Expand Up @@ -95,7 +95,16 @@ else
fi

# 7. SET DEFAULT START COMMAND
echo 'processes = [{ type = "web", command = "bundle exec ruby app.rb"}]' > "$layersdir/launch.toml"
cat > "$layersdir/launch.toml" <<EOL
[[processes]]
type = "web"
command = "bundle exec ruby app.rb"
EOL
cat >> "$layersdir/launch.toml" <<EOL
[[processes]]
type = "worker"
command = "bundle exec ruby worker.rb"
EOL
```

Finally, in your Ruby app directory, create a file named `.ruby-version` with the following contents:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
+++
title="Specify multiple process types"
weight=406
+++

One of the benefits of buildpacks is that they are multi-process - an image can have multiple entrypoints for each operational mode.

Let's see how this works. We will extend our app to have a worker process.

Create a file in the app directory called `worker.rb` with the following contents:

```ruby
for i in 0..5
puts "Running a worker task..."
end
```

After building our app, we could run the resulting image with the `web` process (currently the default) or our new worker process.

To enable running the worker process, we'll need to have our buildpack define a "process type" for the worker. Add the following to the end of your `build` script:

```bash
# Specify the worker process
cat >> "$layersdir/launch.toml" <<EOL
[[processes]]
type = "worker"
command = "bundle exec ruby worker.rb"
EOL
```

Your full `build` script should now look like the following:

```bash
#!/usr/bin/env bash
set -eo pipefail

echo "---> Ruby Buildpack"

# 1. GET ARGS
layersdir=$1

# 2. DOWNLOAD RUBY
echo "---> Downloading and extracting Ruby"
rubylayer="$layersdir"/ruby
mkdir -p "$rubylayer"
ruby_url=https://s3-external-1.amazonaws.com/heroku-buildpack-ruby/heroku-18/ruby-2.5.1.tgz
wget -q -O - "$ruby_url" | tar -xzf - -C "$rubylayer"

# 3. MAKE RUBY AVAILABLE DURING LAUNCH
echo -e 'launch = true' > "$rubylayer.toml"

# 4. MAKE RUBY AVAILABLE TO THIS SCRIPT
export PATH="$rubylayer"/bin:$PATH
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}"$rubylayer/lib"

# 5. INSTALL BUNDLER
echo "---> Installing bundler"
gem install bundler --no-ri --no-rdoc

# 6. INSTALL GEMS
echo "---> Installing gems"
bundle install

# ========== ADDED ===========
# 7. SET DEFAULT START COMMAND
cat > "$layersdir/launch.toml" <<EOL
[[processes]]
type = "web"
command = "bundle exec ruby app.rb"
EOL
cat >> "$layersdir/launch.toml" <<EOL
[[processes]]
type = "worker"
command = "bundle exec ruby worker.rb"
EOL
```

Now if you rebuild your app using the updated buildpack:

```bash
pack build test-ruby-app --path ~/workspace/ruby-sample-app --buildpack ~/workspace/ruby-cnb
```

You should then be able to run your new Ruby worker process:

```bash
docker run --rm --entrypoint worker test-ruby-app
```

and see the worker log output:

```text
Running a worker task...
Running a worker task...
Running a worker task...
Running a worker task...
Running a worker task...
Running a worker task...
```

---

<a href="/docs/buildpack-author-guide/create-buildpack/caching" class="button bg-pink">Next Step</a>