> ## Documentation Index
> Fetch the complete documentation index at: https://cerebrium-fix-make-entrypoint-docs-explicit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Dockerfiles

> Run generic containerized applications on Cerebrium using your own custom Dockerfiles.

For enhanced flexibility, users can bring existing containerized apps to Cerebrium. These can range from standard Python apps to compiled Rust binaries, provided a functional Dockerfile is supplied to build the app.

There are multiple benefits to building using Dockerfiles on Cerebrium, including the ability to bring existing containerized apps to the platform and maintaining consistent deployment environments that are easily managed locally.

## Building Dockerized Python Apps

This example demonstrates a simple FastAPI server that has been containerized:

```python theme={null}
from fastapi import FastAPI

app = FastAPI()

@app.post("/hello")
def hello():
    return {"message": "Hello Cerebrium!"}

@app.get("/health")
def health():
    return "OK"

@app.get("/ready")
def ready():
    return "OK"
```

The application is built using the following Dockerfile:

```dockerfile theme={null}
# Base image
FROM python:3.12-bookworm
RUN apt-get update && apt-get install dumb-init
RUN update-ca-certificates

# Source code
COPY . .

# Dependencies
RUN pip install -r requirements.txt

# Configuration
EXPOSE 8192
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8192"]
```

When creating a Dockerfile for Cerebrium, there are three key requirements:

1. You must expose a port using the `EXPOSE` command - this port will be referenced later in your `cerebrium.toml` configuration
2. Either a `CMD` or `ENTRYPOINT` directive must be defined in your Dockerfile OR the `entrypoint` key in your `cerebrium.toml` under `[runtime.docker]`. This specifies what runs when the container starts. The TOML configuration will take precedence
3. Set the working directory using `WORKDIR` to ensure your application runs from the correct location (defaults to root directory if not specified)

Update cerebrium.toml to include a docker runtime section with the `dockerfile_path` parameter:

```toml theme={null}
[deployment]
name = "my-docker-app"

[runtime.docker]
dockerfile_path = "./Dockerfile"
port = 8192
healthcheck_endpoint = "/health"
readycheck_endpoint = "/ready"
```

The configuration requires the following parameters:

* `dockerfile_path`: The relative path to the Dockerfile used to build the app.
* `port`: The port the server listens on.
* `healthcheck_endpoint`: The endpoint used to confirm instance health. If unspecified, defaults to a TCP ping on the configured port. If the health check registers a non-200 response, it will be considered *unhealthy*, and be restarted should it not recover timely.
* `readycheck_endpoint`: The endpoint used to confirm if the instance is ready to receive. If unspecified, defaults to a TCP ping on the configured port. If the ready check registers a non-200 response, it will not be a viable target for request routing.
* `entrypoint` (optional): The command to start the application. Will be required if `CMD` or `ENTRYPOINT` is not defined in the given dockerfile.

### Entrypoint Precedence

<Info>
  The `entrypoint` parameter in `cerebrium.toml` **always takes precedence**
  over the `CMD` or `ENTRYPOINT` instruction in your Dockerfile. If you specify
  an `entrypoint` in your TOML configuration, it will be used regardless of what
  `CMD` or `ENTRYPOINT` is defined in your Dockerfile.
</Info>

If your Dockerfile does not contain a `CMD` or `ENTRYPOINT` instruction, you **must** specify the `entrypoint` parameter in your `cerebrium.toml`:

```toml theme={null}
[deployment]
name = "my-docker-app"

[runtime.docker]
dockerfile_path = "./Dockerfile"
entrypoint = ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8192"]
port = 8192
healthcheck_endpoint = "/health"
readycheck_endpoint = "/ready"
```

If you want to override your Dockerfile's `CMD` at deploy time without modifying the Dockerfile, simply add the `entrypoint` parameter to your TOML configuration:

```toml theme={null}
[deployment]
name = "my-docker-app"

[runtime.docker]
dockerfile_path = "./Dockerfile"
# This will override any CMD in your Dockerfile
entrypoint = ["python", "server.py", "--port", "8192"]
port = 8192
```

<Warning>
  When specifying a `dockerfile_path`, all dependencies and necessary commands
  should be installed and executed within the Dockerfile. Dependencies listed
  under `dependencies.*`, as well as `shell_commands` and `pre_build_commands`,
  will be ignored.
</Warning>

## Building Generic Dockerized Apps

Cerebrium supports apps in languages other than Python, provided a Dockerfile is supplied. The following example demonstrates a Rust-based API server using the Axum framework:

```rust theme={null}
use axum::{
    routing::{get, post},
    Json, Router,
};
use serde_json::json;

async fn hello() -> Json<serde_json::Value> {
    Json(json!({ "message": "Hello Cerebrium!" }))
}

async fn health() -> &'static str {
    "OK"
}


async fn ready() -> &'static str {
    "OK"
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/hello", post(hello))
        .route("/health", get(health))
        .route("/ready", get(health));
    tracing::info!("Listening on port 8192");

    let listener = tokio::net::TcpListener::bind("0.0.0.0:8192").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}
```

In this case, a multi-stage Dockerfile is used to separate the build step, creating a smaller and more secure image for the runtime:

```dockerfile theme={null}
# Build stage
FROM rust:bookworm as build
RUN apt-get update && apt-get install dumb-init
RUN update-ca-certificates

# Project setup
RUN USER=root cargo new --bin rs_server
WORKDIR /rs_server

# Dependencies
COPY Cargo.lock ./Cargo.lock
COPY Cargo.toml ./Cargo.toml

# Cache dependencies
RUN cargo build --release
RUN rm src/*.rs

# Source code
COPY src/* src/

# Build
RUN rm ./target/release/deps/rs_server*
RUN cargo build --release

# Runtime stage
FROM gcr.io/distroless/base-debian12
WORKDIR /
COPY --from=build  /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=build /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/x86_64-linux-gnu/libgcc_s.so.1
COPY --from=build /rs_server/target/release/rs_server /rs_server
COPY --from=build /usr/bin/dumb-init /usr/bin/dumb-init
EXPOSE 8192
CMD ["dumb-init", "--", "/rs_server"]
```

Similarly to the FastAPI webserver, the application should be configured in the `cerebrium.toml` file:

```toml theme={null}
[deployment]
name = "rust-server"

[runtime.docker]
dockerfile_path = "./Dockerfile"
port = 8192
healthcheck_endpoint = "/health"
readycheck_endpoint = "/ready"
```
