|
| 1 | +--- |
| 2 | +meta: |
| 3 | + title: How to move from Serverless Functions to Serverless Containers |
| 4 | + description: Learn how to migrate your workloads from Scaleway Serverless Functions to Serverless Containers for greater control and flexibility. |
| 5 | + dates: |
| 6 | + validation: 2025-11-25 |
| 7 | + posted: 2025-11-25 |
| 8 | +--- |
| 9 | +import Requirements from '@macros/iam/requirements.mdx' |
| 10 | + |
| 11 | + |
| 12 | +Serverless Functions and Serverless Containers share the same architecture (based on Knative). |
| 13 | +When you deploy a Function, Scaleway simply injects your code into a pre-built container image. |
| 14 | + |
| 15 | +Migrating to Serverless Containers just means you take control of that container image creation yourself. |
| 16 | + |
| 17 | +<Requirements /> |
| 18 | + |
| 19 | +## Understanding the differences |
| 20 | + |
| 21 | +Scaleway Serverless Functions allow you to quickly deploy snippets of code without worrying about anything but the business logic. |
| 22 | + |
| 23 | +* **Best for:** Webhooks, lightweight APIs, and glue code. |
| 24 | +* **Key benefit:** "Zero config" deployment—just paste your code and go. |
| 25 | + |
| 26 | +However, as your application grows, you face limitations regarding dependency management (e.g., needing system-level libraries like ffmpeg or specific C extensions), or complex build pipelines. |
| 27 | + |
| 28 | +This is where Serverless Containers can be more adapted. |
| 29 | + |
| 30 | +**Moving to Containers means:** |
| 31 | + |
| 32 | +* You take control of the "wrapping": Instead of Scaleway wrapping your code, you write a Dockerfile. |
| 33 | +* You gain flexibility: You can install any system library, use any language version, and control the exact OS environment. |
| 34 | +* Better portability: A containerized app can run on Scaleway, your local machine, or any other cloud provider without changing the code. |
| 35 | + |
| 36 | +## When to migrate to Serverless Containers? |
| 37 | + |
| 38 | +While Functions are excellent for "zero-config" deployments, Serverless Containers are the recommended choice when your project requirements expand. |
| 39 | + |
| 40 | +Consider migrating if: |
| 41 | + |
| 42 | +* **You need custom system dependencies:** Functions run in a managed environment. If your code requires specific system libraries (e.g., `ffmpeg`, `ImageMagick`, custom C-bindings) that are not present in the standard runtime, containers allow you to install them via the Dockerfile. |
| 43 | + |
| 44 | +* **You need full portability:** A Docker container is the industry standard for shipping code. By containerizing your application, you ensure it can run anywhere: on your local machine, on various Scaleway products, on Kubernetes clusters, or any other cloud provider, without changing a single line of code. |
| 45 | + |
| 46 | +* **You need a specific language version:** Serverless Functions support a specific list of runtimes (e.g., Node 22, Python 3.13). If you need an older version, a beta version, or a completely different language (like Java, Ruby, or .NET), Serverless Containers are the solution. |
| 47 | + |
| 48 | +* **You have a complex build pipeline:** If your application requires a compilation step, complex asset building, or private package managers, defining these steps in a `Dockerfile` gives you granular control over the build process. |
| 49 | + |
| 50 | +## Containerize your Serverless Function |
| 51 | + |
| 52 | +The main step in migrating is creating a `Dockerfile` that replicates the runtime environment your function was using. |
| 53 | + |
| 54 | +Below are standard `Dockerfile` templates for the main Serverless Functions runtimes. You can add this file to the root of your project (where your `handler` or `index` file is located). |
| 55 | + |
| 56 | +<Message type="important"> |
| 57 | + Scaleway Serverless Containers inject a `PORT` environment variable (defaulting to `8080`). Your application must listen on this port to receive traffic. |
| 58 | +</Message> |
| 59 | + |
| 60 | +<Tabs id="runtimes"> |
| 61 | + <TabsTab label="Node 22"> |
| 62 | + Use this Dockerfile to migrate from the **Node.js 22** runtime. |
| 63 | + |
| 64 | + ```dockerfile |
| 65 | + # Use the official Node.js 22 Alpine image for a small footprint |
| 66 | + FROM node:22-alpine |
| 67 | + |
| 68 | + # Set the working directory |
| 69 | + WORKDIR /usr/src/app |
| 70 | + |
| 71 | + # Copy package files first to leverage Docker cache |
| 72 | + COPY package*.json ./ |
| 73 | + |
| 74 | + # Install production dependencies |
| 75 | + RUN npm ci --only=production |
| 76 | + |
| 77 | + # Copy the rest of your application code |
| 78 | + COPY . . |
| 79 | + |
| 80 | + # Serverless Containers inject the PORT env var (default 8080) |
| 81 | + ENV PORT 8080 |
| 82 | + EXPOSE 8080 |
| 83 | + |
| 84 | + # Start the application |
| 85 | + CMD [ "node", "index.js" ] |
| 86 | + ``` |
| 87 | + </TabsTab> |
| 88 | + |
| 89 | + <TabsTab label="Python 3.13"> |
| 90 | + Use this Dockerfile to migrate from the **Python 3.13** runtime. We recommend using a WSGI server like Gunicorn for production. |
| 91 | + |
| 92 | + ```dockerfile |
| 93 | + # Use the official Python 3.13 slim image |
| 94 | + FROM python:3.13-slim |
| 95 | + |
| 96 | + WORKDIR /app |
| 97 | + |
| 98 | + # Copy requirements and install dependencies |
| 99 | + COPY requirements.txt . |
| 100 | + RUN pip install --no-cache-dir -r requirements.txt |
| 101 | + |
| 102 | + # Copy application code |
| 103 | + COPY . . |
| 104 | + |
| 105 | + # Define the default port |
| 106 | + ENV PORT 8080 |
| 107 | + EXPOSE 8080 |
| 108 | + |
| 109 | + # Run the application using Gunicorn |
| 110 | + # Replace 'main:app' with 'your_filename:your_flask_object' |
| 111 | + CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app |
| 112 | + ``` |
| 113 | + </TabsTab> |
| 114 | + |
| 115 | + <TabsTab label="Go 1.24"> |
| 116 | + Use this Dockerfile to migrate from the **Go 1.24** runtime. This uses a multi-stage build to keep the final image lightweight. |
| 117 | + |
| 118 | + ```dockerfile |
| 119 | + # --- Build Stage --- |
| 120 | + FROM golang:1.24-alpine AS builder |
| 121 | + |
| 122 | + WORKDIR /app |
| 123 | + |
| 124 | + # Copy module files and download dependencies |
| 125 | + COPY go.mod go.sum ./ |
| 126 | + RUN go mod download |
| 127 | + |
| 128 | + # Copy source code |
| 129 | + COPY . . |
| 130 | + |
| 131 | + # Build the binary |
| 132 | + RUN CGO_ENABLED=0 GOOS=linux go build -o my-function . |
| 133 | + |
| 134 | + # --- Run Stage --- |
| 135 | + FROM alpine:latest |
| 136 | + |
| 137 | + WORKDIR /root/ |
| 138 | + |
| 139 | + # Copy the binary from the builder |
| 140 | + COPY --from=builder /app/my-function . |
| 141 | + |
| 142 | + # Install certificates for HTTPS calls |
| 143 | + RUN apk --no-cache add ca-certificates |
| 144 | + |
| 145 | + ENV PORT 8080 |
| 146 | + EXPOSE 8080 |
| 147 | + |
| 148 | + CMD ["./my-function"] |
| 149 | + ``` |
| 150 | + </TabsTab> |
| 151 | + |
| 152 | + <TabsTab label="Rust 1.85"> |
| 153 | + Use this Dockerfile to migrate from the **Rust 1.74** runtime. |
| 154 | + |
| 155 | + ```dockerfile |
| 156 | + # --- Build Stage --- |
| 157 | + FROM rust:1.85-slim as builder |
| 158 | + |
| 159 | + WORKDIR /usr/src/app |
| 160 | + |
| 161 | + # Create a new empty shell project |
| 162 | + RUN USER=root cargo new --bin my-app |
| 163 | + WORKDIR /usr/src/app/my-app |
| 164 | + |
| 165 | + # Copy manifests |
| 166 | + COPY Cargo.toml Cargo.lock ./ |
| 167 | + |
| 168 | + # Build only the dependencies to cache them |
| 169 | + RUN cargo build --release |
| 170 | + |
| 171 | + # Remove the dummy source |
| 172 | + RUN rm src/*.rs |
| 173 | + |
| 174 | + # Copy your actual source code |
| 175 | + COPY ./src ./src |
| 176 | + |
| 177 | + # Build for release |
| 178 | + RUN rm ./target/release/deps/my_app* |
| 179 | + RUN cargo build --release |
| 180 | + |
| 181 | + # --- Run Stage --- |
| 182 | + FROM debian:bookworm-slim |
| 183 | + |
| 184 | + # Install OpenSSL if required |
| 185 | + RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/* |
| 186 | + |
| 187 | + COPY --from=builder /usr/src/app/my-app/target/release/my-app /usr/local/bin/my-app |
| 188 | + |
| 189 | + ENV PORT 8080 |
| 190 | + EXPOSE 8080 |
| 191 | + |
| 192 | + CMD ["my-app"] |
| 193 | + ``` |
| 194 | + </TabsTab> |
| 195 | + |
| 196 | + <TabsTab label="PHP 8.4"> |
| 197 | + Use this Dockerfile to migrate from the **PHP 8.4** runtime. |
| 198 | + |
| 199 | + ```dockerfile |
| 200 | + # Use the official PHP 8.4 Apache image |
| 201 | + FROM php:8.4-apache |
| 202 | + |
| 203 | + WORKDIR /var/www/html |
| 204 | + |
| 205 | + # Copy application source |
| 206 | + COPY . . |
| 207 | + |
| 208 | + # Configure Apache to listen on the Scaleway PORT env var |
| 209 | + RUN sed -i 's/80/${PORT}/g' /etc/apache2/sites-available/000-default.conf /etc/apache2/ports.conf |
| 210 | + |
| 211 | + # Install required extensions (Example) |
| 212 | + # RUN docker-php-ext-install pdo pdo_mysql |
| 213 | + |
| 214 | + ENV PORT 8080 |
| 215 | + EXPOSE 8080 |
| 216 | + |
| 217 | + CMD ["apache2-foreground"] |
| 218 | + ``` |
| 219 | + </TabsTab> |
| 220 | +</Tabs> |
| 221 | + |
| 222 | +## Build and push the image |
| 223 | + |
| 224 | +Once your `Dockerfile` is ready, you need to build the image and push it to your Scaleway Container Registry. |
| 225 | + |
| 226 | +1. Log in to your registry: |
| 227 | + ```bash |
| 228 | + docker login rg.fr-par.scw.cloud/your-namespace -u nologin --password-stdin <<< "$SCW_SECRET_KEY" |
| 229 | + ``` |
| 230 | +2. Build the image: |
| 231 | + ```bash |
| 232 | + docker build -t my-migrated-function:latest . |
| 233 | + ``` |
| 234 | +3. Tag and push the image: |
| 235 | + ```bash |
| 236 | + docker tag my-migrated-function:latest rg.fr-par.scw.cloud/your-namespace/my-migrated-function:latest |
| 237 | + docker push |
| 238 | + ``` |
| 239 | + |
| 240 | +Refer to the [dedicated documentation](/serverless-containers/how-to/build-push-container-image/) for more information on how to build and push images to the Scaleway Container Registry. |
| 241 | + |
| 242 | +## Deploy to Serverless Containers |
| 243 | + |
| 244 | +1. Navigate to **Serverless Containers** in the [Scaleway console](https://console.scaleway.com). |
| 245 | +2. Click **Deploy container**. |
| 246 | +3. Select **Scaleway Container Registry** and choose the image you just pushed (`my-migrated-function`). |
| 247 | +4. Set the **Port** to `8080` (or match the `PORT` environment variable in your Dockerfile). |
| 248 | +5. Set the same resources (vCPU/RAM) and scaling parameters (min/max scale) as your original function. |
| 249 | +6. Click **Deploy**. |
| 250 | + |
| 251 | +Your code is now running as a Serverless Container, giving you the freedom to modify the OS, install binaries, and manage complex dependencies exactly as you need. |
| 252 | + |
| 253 | +## Additional content |
| 254 | + |
| 255 | +For advanced usage, such as larger projects with dependencies, automation, and more, check out our [GitHub repository](https://github.com/scaleway/serverless-examples) for more examples. |
| 256 | + |
0 commit comments