diff --git a/mkdocs.yml b/mkdocs.yml index 164c4ce..92ce99e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: tsuru +site_name: Tsuru Docs site_url: https://docs.github.com site_author: Tsuru @@ -13,7 +13,36 @@ theme: palette: primary: black + features: + - content.code.copy + - content.code.select + - navigation.instant + - navigation.tracking + - navigation.tabs + - toc.follow + +markdown_extensions: +- admonition +- footnotes +- pymdownx.details +- pymdownx.highlight +- pymdownx.snippets: + base_path: + - src/ +- pymdownx.superfences +- pymdownx.tabbed: + alternate_style: true +- toc: + permalink: true + docs_dir: src nav: -- Home: src/index.md +- Home: index.md +- Getting started: [] +- User guides: + - Deploy: + - Using Dockerfile: ./user_guides/deploy_using_dockerfile.md +- Admin guides: [] +- References: [] +- Contributing: [] diff --git a/poetry.lock b/poetry.lock index 8ae5097..72065e5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -614,4 +614,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "b9a7878d3e559fe04bd8f92c074d2c8dd67aa6664388ce7aefa0445984cc6d25" +content-hash = "0d827a2926ce554e24ec34da226083d2aacc6fa2add8a6dddf6f175a88d71bc3" diff --git a/pyproject.toml b/pyproject.toml index a0a546c..de5dee7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ readme = "README.md" python = "^3.11" mkdocs = "^1.4.3" mkdocs-material = "^9.1.17" +pymdown-extensions = "^10.0.1" [build-system] requires = ["poetry-core"] diff --git a/src/static/samples/dockerfile_v1/Dockerfile b/src/static/samples/dockerfile_v1/Dockerfile new file mode 100644 index 0000000..7590e86 --- /dev/null +++ b/src/static/samples/dockerfile_v1/Dockerfile @@ -0,0 +1,24 @@ +FROM golang:1.20-alpine3.17 AS builder +COPY ./ /go/app/ +RUN set -x \ + && cd /go/app\ + && CGO_ENABLED=0 go build -o server ./main.go + +# NOTE: Tsuru doesn't support deploy of distroless container images. +FROM alpine:3.17 + +# You should always set the working dir so Tsuru will try to find the config +# files (Procfile, tsuru.yaml) from there. +WORKDIR /var/app + +# Copying generated file from previous build stage \o/ +COPY --from=builder /go/app/server /var/app/ + +# Copying app's config file to working dir. +COPY ./tsuru.yaml /var/app + +# NOTE: Container runtime doesn't expand the env var ($PORT), so we have to +# call a shell interpreter to do so. +# +# See more: https://github.com/moby/moby/issues/5509 +CMD ["sh", "-c", "/var/app/server -port $PORT"] diff --git a/src/static/samples/dockerfile_v1/go.mod b/src/static/samples/dockerfile_v1/go.mod new file mode 100644 index 0000000..f3ef144 --- /dev/null +++ b/src/static/samples/dockerfile_v1/go.mod @@ -0,0 +1,3 @@ +module github.com/tsuru/samples/dockerfile_v1 + +go 1.20 diff --git a/src/static/samples/dockerfile_v1/main.go b/src/static/samples/dockerfile_v1/main.go new file mode 100644 index 0000000..4f65429 --- /dev/null +++ b/src/static/samples/dockerfile_v1/main.go @@ -0,0 +1,39 @@ +package main + +import ( + "flag" + "fmt" + "net/http" +) + +func main() { + var port int + + flag.IntVar(&port, "port", 8080, "TCP port number where app should wait for connections") + flag.Parse() + + mux := http.NewServeMux() + mux.HandleFunc("/healthz", healthz) + mux.HandleFunc("/", hello) + + address := fmt.Sprintf(":%d", port) + + fmt.Println("Running web server on", address) + + server := &http.Server{ + Addr: address, + Handler: mux, + } + + server.ListenAndServe() + + fmt.Println("Web server turned off") +} + +func healthz(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "WORKING") +} + +func hello(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "Hello world!") +} diff --git a/src/static/samples/dockerfile_v1/tsuru.yaml b/src/static/samples/dockerfile_v1/tsuru.yaml new file mode 100644 index 0000000..a2c3b84 --- /dev/null +++ b/src/static/samples/dockerfile_v1/tsuru.yaml @@ -0,0 +1,2 @@ +healthcheck: + path: /healthz diff --git a/src/user_guides/deploy_using_dockerfile.md b/src/user_guides/deploy_using_dockerfile.md new file mode 100644 index 0000000..2a00c0b --- /dev/null +++ b/src/user_guides/deploy_using_dockerfile.md @@ -0,0 +1,109 @@ +# Deploy using Dockerfile + +The Tsuru official platforms do not support every language, framework, or runtime that your tech stack may require, nor do they intend to. +If you have a setup where the official platforms do not meet your needs, you have the option to deploy your app using its [Dockerfile][Dockerfile reference] (Containerfile). + +!!! note "Comparison: container image x Dockerfile" + + The key difference between deploying an app using a container image and a Dockerfile lies in the developer's convenience. + The former requires additional steps on the developer's side, such as building and publishing the container image, while the latter eliminates these requirements. + +## Usage + +The command argument `--dockerfile` (in the `tsuru app deploy` command) is the main difference among other types of deploy on Tsuru. +It defines the container file that generates the container image used in the following steps of the app's deployment process. +Along this command, you also can pass all deployable files to the app - these files will be available in the container image build context, so you can select these using the [COPY](https://docs.docker.com/engine/reference/builder/#copy)/[ADD](https://docs.docker.com/engine/reference/builder/#add) directives. + +The anatomy of app deploy using Dockerfile follows: + +``` { .bash .no-copy } +tsuru app deploy -a \ + --dockerfile [--] [DEPLOYABLE FILES...] +``` + +The `--dockerfile` command argument value can be either a regular file or a directory. +When specifying a regular file, you have the explicit choice to select the container file. +On the other hand, when using a directory, the container file is implicitly chosen (see the heuristic mentioned below). + +???+ notice "Heuristics for implicit container file name" + + When you pass a directory as argument value of `--dockerfile`, the Tsuru client tries to find the container file following these names (order matters): + + 1. `Dockerfile.` (e.g. `Dockerfile.my-example-app`) + 2. `Containerfile.` (e.g. `Containerfile.my-example-app`) + 3. `Dockerfile.tsuru` + 4. `Containerfile.tsuru` + 5. `Dockerfile` + 6. `Containerfile` + + The chosen file will be the first one that exists and can be read correctly. + +In both cases, you can push the deployable file(s) to `tsuru app deploy` passing as command arguments (positional args in the end of command). +Those files can either be regular files, directories or symbolic links. +Thoses files will be available in the container image build context and you shoul pick them usin `COPY`/`ADD` directives inside the container image. + +???+ tip "Excluding deployable files with ignore files (`.tsuruignore` and `.dockerignore`)" + + Please note that any deployable files can be excluded if they match a rule specified in the Tsuru ignore file (namely `.tsuruignore`) located in the current directory. + Furthermore, when deploying using a Dockerfile, the Tsuru client also takes into account the Docker ignore file (namely `.dockerfile`) in the current directory to exclude specific files. + +### Example + +In this example, we are about to build and deploy an app written in Golang. +You can copy and paste the used files below (separated by tabs) - before you might want take a closer look at them, specially at `Dockerfile` and `main.go` files. + + +=== "Dockerfile" + + ``` dockerfile + --8<-- "static/samples/dockerfile_v1/Dockerfile" + ``` + +=== "main.go" + + ``` golang + --8<-- "static/samples/dockerfile_v1/main.go" + ``` + +=== "go.mod" + + ``` gomod + --8<-- "static/samples/dockerfile_v1/go.mod" + ``` + +=== "tsuru.yaml" + + ``` yaml + --8<-- "static/samples/dockerfile_v1/tsuru.yaml" + ``` + +To deploy into application `my-example-app` using its Dockerfile, you just need issue the below command: + +``` bash +tsuru app deploy -a my-example-app --dockerfile . +``` + +## Advanced + +### How can I access Tsuru env vars during container image build? + +You are able to import the env vars configured on Tsuru app while running the deploy with Dockerfile. +To do so, you just need append the following snippet in the Dockerfile. + +``` dockerfile +RUN --mount=type=secret,id=tsuru-app-envvars,target=/var/run/secrets/envs.sh \ + && . /var/run/secrets/envs.sh \ + ... following commands in this multi-command line are able to see the env vars from Tsuru +``` + +**NOTE**: That's a bit different than defining `ENV` directive, specially because they're not stored in the image layers. + +## Limitations + +1. You cannot use distroless based images on your final container image - although on intermediary stages is fine.[^1] +2. There's no support for setting build arguments. +3. There's no support to specify a particular platform - the only platform supported is `linux/amd64`. + +[^1]: Tsuru requires a shell intepreter (e.g. `sh` or `bash`) to run hooks, app shell, etc. + +[Dockerfile reference]: https://docs.docker.com/engine/reference/builder/