You are viewing Nextmv legacy docs. ⚡️ Go to latest docs ⚡️

Deployment

Docker Http Runner

Overview of deploying to docker with the HTTP runner.

Nextmv engines and apps are capable of being deployed to Docker containers. The following recipe demonstrates building and deploying our Knapsack engine into a Docker container using the HTTP runner. We make HTTP requests to it using curl.

Files

This recipe can be built in any directory. We use knapsack-http as the top level folder. We will create the following files.

knapsack-http
├── Dockerfile
├── data
│   └── input-11items.json
├── knapsack-http
├── go.mod
├── go.sum
└── main.go
Copy

Dockerfile

Create a Dockerfile in the project root that contains the following code.

FROM gcr.io/distroless/static:nonroot
ENV HOP_RUNNER_OUTPUT_SOLUTIONS last
ENV HOP_SOLVER_LIMITS_DURATION 1s
COPY knapsack-http /
ENTRYPOINT ["/knapsack-http", "-hop.runner.http.address", ":5000"]
Copy

We use a "distroless" base Docker image. We set environment variables in the image to limit model runtime and to return only the last solution in the HTTP response.

More configuration options can be found in the Environment Variables and CLI Options section of our docs. The COPY command copies the executable from our local machine to the Docker image. The ENTRYPOINT configures our container as an executable that accepts input parameters.

main.go

Within the model's main.go file import the HTTP runner and call it in the main() function.

package main

import (
    "github.com/nextmv-io/code/hop/run/http"
    "github.com/nextmv-io/code/engines/pack/knapsack"
)

func main() {
    http.Run(knapsack.DefaultSolver)
}
Copy

data/input-11items.json

We can use the same data file from the CLI runner recipe for testing this one.

Docker

Building a binary executable

To download and install the packages needed to build our binary we run the following commands at the root of the project.

go mod init knapsack-http
go get ./...
Copy

First, we create a go.mod file which defines the import path of the current Go module as well as other dependencies. This is done by running the command go mod init on the root of the project. Next, run go get ./.... You'll notice that a go.sum file is created on the project's root. This contains a list of hashes associated to each package to ensure the same files are used for each build.

To build our executable we then run the following commands:

CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -o knapsack-http
Copy

Here, we set environment variables so Go cross compiles the binary for a Linux operating system. The go build command builds an executable from the model's main.go file.

Building a Docker image

To build a Docker image, run the following command from the the root of the project.

docker build -t example-nextmv/knapsack-http .
Copy

docker build constructs a Docker image based on the contents of our Dockerfile. Note that the image is automatically tagged with latest. If we want to version the image, we add a tag to the build command.

Running a Docker container

Once the setup is complete, from your terminal you can run the Docker container:

docker run --rm -d -p 8080:5000 example-nextmv/knapsack-http
Copy

The --rm flag cleans up the container after it finishes execution. -d allows us to run our container in the background. To see error messages use docker logs. The -p flag exposes port 8080 and binds it to port 5000 of the Docker container. Our container is now ready to receive requests.

curl -d @data/input-11items.json localhost:8080
Copy

In the terminal, the server response will include the model's solution.

Using a web server

We can also put a reverse proxy in front of our knapsack-http using NGINX. This gives us useful web server features such as load balancing, request queues and caching.

Create a folder called knapsack/, move the Dockerfile, main.go, go.mod, go.sum and the knapsack-http binary to the knapsack/ folder. Then, create a separate folder at the same level as the knapsack/ folder called nginx/. Inside the nginx/ folder create a Dockerfile and an nginx.conf file. In the NGINX Dockerfile add the following:

FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/
Copy

This removes the existing configuration file (default.conf) and replaces it with our own. Add the following to an nginx.conf file. You may wish to replace the knapsack-http placeholder with the name of your project:

worker_processes 1;

events {
  worker_connections 1024;
}

http {
  upstream knapsack {
    server knapsack-http_knapsack_1:5000;
  }

  server {
    listen 8080;

    location / {
        proxy_pass http://knapsack;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto http;
    }
  }
}
Copy

Our NGINX reverse proxy will route requests from the container knapsack-http_nginx_1 to the container knapsack-http_knapsack_1. Docker automatically aliases container names to their IP addresses. Finally, create a docker-compose.yml file at the root of the project.

services:
  knapsack:
    build: ./knapsack/
  nginx:
    build: ./nginx/
    ports:
      - 8080:8080
    depends_on:
      - knapsack
Copy

Your file structure should look like the following:

knapsack-http
├── data
│   └── input-11items.json
├── docker-compose.yml
├── knapsack
│   ├── Dockerfile
│   ├── go.mod
│   ├── go.sum
│   ├── knapsack-http
│   └── main.go
└── nginx
    ├── Dockerfile
    └── nginx.conf
Copy

Now docker stop the existing knapsack-http and use Docker Compose to bring up both Hop and NGINX.

docker-compose -p knapsack-http up -d
Copy

The -p flag specifies the project name. If the -p flag is not provided Docker will use the folder name instead. The -d flag sets the container to run in "detached" mode. You can post the input file to the web server using the command:

curl -d @data/input-11items.json localhost:8080
Copy

If any changes to the nginx.conf file or knapsack binary are made you will need to rebuild the Docker images. This can be done with docker-compose build.

Page last updated

Go to on-page nav menu