Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
cyrildiagne committed Jan 12, 2020
1 parent c2c6ce0 commit 1e69ecd
Show file tree
Hide file tree
Showing 57 changed files with 205 additions and 190 deletions.
62 changes: 43 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,48 @@

**Status:** 🧪Experimental

## Turn any model into a serverless API
Kuda's goal is to make it **easy** and **inexpensive** to add cloud GPUs to any webapp.

Easily turn any model into a serverless API that will consume cloud GPUs only
when it's being called.
## Serverless GPU inference

Kuda deploys your API as a docker container, so you can use any language, any
framework, and there is no library to import in your code.
Kuda builds on [Knative](#) to allocate cloud GPUs only when there is traffic to your app.

All you need is a Dockerfile.
This is ideal when you want to share your prototypes online without keeping expensive GPUs allocated all the time.

## Easy to use
It tries to reduce cold starts time (gpu nodes allocation and service instanciation) as much possible and to tries manage cooldown times intelligently.

- `kuda init` Initializes your local & remote configurations
- `kuda dev` Deploys the API in dev mode (with file sync & live reload)
- `kuda deploy` Deploys the API in production mode
- `kuda publish` Publishes the API template to the registry
## Add GPU models to a webapp easily

## Features
- Deploy a template from github

- Provision GPUs & scale based on traffic (from zero to N)
- Interactive development on cloud GPUs from any workstation
- Protect & control access to your APIs using API Keys
- HTTPS with TLS termination & automatic certificate management
```bash
kuda deploy -f github.com/cyrildiagne/gpt2-http
```

- Call your deployed API

```bash
$ curl \
-H 'x-api-key: $your_key' \
-F 'input=Kuda is' \
https://gpt2.<your-namespace>.kuda.cloud/generate
```

```json
{
"query": "Kuda is",
"generated": "a tool that...etc."
}
```

## Use the frameworks you know
Checkout the full list of templates available in [the registry](#).

## Turn any model into a serverless API

Kuda deploys APIs as a docker containers, so you can use any language, any
framework, and there is no library to import in your code.

All you need is a Dockerfile.

Here's a minimal example that just prints the result of `nvidia-smi` using
[Flask](http://flask.palletsprojects.com):
Expand Down Expand Up @@ -70,10 +87,10 @@ deploy:
```
Running `kuda deploy` in this example would build and deploy the API to a url
such as `https://hello-gpu.default.yourdomain.com` which you can easily call:
such as `https://hello-gpu.my-namespace.kuda.cloud` which you can easily call:

```
$ curl https://hello-gpu.default.yourdomain.com
$ curl https://hello-gpu.my-namespace.kuda.cloud
Hello GPU!
Expand All @@ -99,6 +116,13 @@ Hello GPU!
Checkout the full example with annotations in
[examples/hello-gpu-flask](examples/hello-gpu-flask).

## Features

- Provision GPUs & scale based on traffic (from zero to N)
- Interactive development on cloud GPUs from any workstation
- Protect & control access to your APIs using API Keys
- HTTPS with TLS termination & automatic certificate management

## Get Started

- [Install](docs/install_cli.md)
Expand Down
7 changes: 0 additions & 7 deletions cli/main.go

This file was deleted.

11 changes: 6 additions & 5 deletions images/deployer/main.go → cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"net/http"
"os"

"github.com/cyrildiagne/kuda/pkg/deployer"
"github.com/cyrildiagne/kuda/pkg/api"
"github.com/cyrildiagne/kuda/pkg/deploy"
"github.com/cyrildiagne/kuda/pkg/gcloud"

"github.com/gorilla/mux"
Expand Down Expand Up @@ -36,7 +37,7 @@ func main() {
log.Fatalf("error initializing firebase: %v\n", err)
}

env := &deployer.Env{
env := &api.Env{
GCPProjectID: gcpProjectID,
DB: fs,
Auth: auth,
Expand All @@ -53,15 +54,15 @@ func main() {
if value, ok := os.LookupEnv("port"); ok {
port = value
}
fmt.Println("Starting deployer on port", port)
fmt.Println("Starting api on port", port)

r := mux.NewRouter()
r.HandleFunc("/", handleRoot).Methods("GET")

deployHandler := deployer.Handler{Env: env, H: deployer.HandleDeploy}
deployHandler := api.Handler{Env: env, H: deploy.HandleDeploy}
r.Handle("/deploy", deployHandler).Methods("POST")

publishHandler := deployer.Handler{Env: env, H: deployer.HandlePublish}
publishHandler := api.Handler{Env: env, H: deploy.HandlePublish}
r.Handle("/publish", publishHandler).Methods("POST")

http.ListenAndServe(":"+port, r)
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/auth.go → cmd/cli/auth.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package main

import (
"context"
Expand Down
6 changes: 3 additions & 3 deletions cli/cmd/deploy.go → cmd/cli/deploy.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package main

import (
"bufio"
Expand Down Expand Up @@ -43,7 +43,7 @@ func deployFromPublished(published string) error {
params.Set("from_published", published)
body := strings.NewReader(params.Encode())

url := cfg.Provider.DeployerURL + "/deploy"
url := cfg.Provider.ApiURL + "/deploy"
req, err := http.NewRequest("POST", url, body)
if err != nil {
return err
Expand Down Expand Up @@ -118,7 +118,7 @@ func deploy(manifest *latest.Manifest) error {
writer.Close()

// Create request.
url := cfg.Provider.DeployerURL + "/deploy"
url := cfg.Provider.ApiURL + "/deploy"
req, err := http.NewRequest("POST", url, body)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion cli/cmd/dev.go → cmd/cli/dev.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package main

import (
"fmt"
Expand Down
16 changes: 8 additions & 8 deletions cli/cmd/init.go → cmd/cli/init.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package main

import (
"fmt"
Expand Down Expand Up @@ -30,14 +30,14 @@ var initCmd = &cobra.Command{
if authURLFlag != "" {
authURL = authURLFlag
}
deployerURL := "https://deployer." + provider
deployerURLFlag, _ := cmd.Flags().GetString("deployer_url")
if deployerURLFlag != "" {
deployerURL = deployerURLFlag
apiURL := "https://api." + provider
apiURLFlag, _ := cmd.Flags().GetString("api_url")
if apiURLFlag != "" {
apiURL = apiURLFlag
}
newCfg.Provider = config.ProviderConfig{
AuthURL: authURL,
DeployerURL: deployerURL,
AuthURL: authURL,
ApiURL: apiURL,
}

// Start login flow.
Expand All @@ -60,7 +60,7 @@ func init() {

initCmd.Flags().StringP("provider", "p", "kuda.cloud", "Knative namespace.")
initCmd.Flags().String("auth_url", "", "Authentication URL.")
initCmd.Flags().String("deployer_url", "", "Deployer URL.")
initCmd.Flags().String("api_url", "", "Deployer URL.")
}

func writeConfig(cfg config.UserConfig) error {
Expand Down
6 changes: 2 additions & 4 deletions cli/cmd/root.go → cmd/cli/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package main

import (
"fmt"
Expand Down Expand Up @@ -26,9 +26,7 @@ var RootCmd = &cobra.Command{
Version: version,
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the RootCmd.
func Execute() {
func main() {
RootCmd.Version = version
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
Expand Down
4 changes: 2 additions & 2 deletions cli/cmd/publish.go → cmd/cli/publish.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cmd
package main

import (
"bytes"
Expand Down Expand Up @@ -51,7 +51,7 @@ func publish(manifest *latest.Manifest) error {
writer.Close()

// Create request.
url := cfg.Provider.DeployerURL + "/publish"
url := cfg.Provider.ApiURL + "/publish"
req, err := http.NewRequest("POST", url, body)
if err != nil {
return err
Expand Down
4 changes: 2 additions & 2 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Initializes the local configuration.
**Flags**

- `[-p, --provider]` The provider root URL (default: `kuda.cloud`).
- `[--auth-url]` Specify which url to use for authentication when using a remote deployer. (default: `auth.<provider>`)
- `[--deployer-url]` Specify which url to use for deployment when using a remote deployer. (default: `deployer.<provider>`)
- `[--auth-url]` Specify which url to use for authentication. (default: `auth.<provider>`)
- `[--api-url]` Specify which url to use as remote api. (default: `api.<provider>`)

**Examples**

Expand Down
6 changes: 3 additions & 3 deletions examples/hello-gpu-flask/kuda.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ name: hello-gpu
# (Optional) Version of the API.
version: 0.1.0

# 'deploy' is the config used when running `kuda deploy`.
# `deploy` is the config used when running `kuda deploy`.
# It has sensible defaults but you can override all the properpties.
deploy:
dockerfile: ./Dockerfile

# 'dev' is the config used when running `kuda dev`.
# (Optional) `dev` is used when running `kuda dev`.
# It inherits all properties from 'deploy' which you can override individually.
dev:
# Use python3 to start the Flask dev server rather than gunicorn.
Expand All @@ -26,7 +26,7 @@ dev:
- name: FLASK_ENV
value: development

# 'paths' is optional. It lets you specify how to interact with the API.
# (Optional) `paths` lets you specify how clients interact with the API.
# It follows the OpenAPI 3.0 specification.
# It is only required when publishing to a registry.
paths:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion images/adapter/README.md → install/adapter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ docker run --rm \
-p 44225:44225 \
-e FIRESTORE_CREDENTIALS="/path/YOUR_CREDENTIALS.json" \
-v /path/to/local/credentials/folder:/secret \
gcr.io/kuda-project/kuda-mixer-adapter
gcr.io/kuda-cloud/kuda-mixer-adapter
```

Send a mock Authorization request:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ spec:
spec:
containers:
- name: kuda-mixer-adapter
image: gcr.io/kuda-project/kuda-mixer-adapter
image: gcr.io/kuda-cloud/kuda-mixer-adapter
imagePullPolicy: Always
ports:
- containerPort: 44225
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ metadata:
spec:
# match: match(destination.service.host, "*.svc.cluster.local") && !match(destination.service.host, "*.kuda.svc.cluster.local") && match(context.reporter.uid, "kubernetes://istio-ingressgateway-*")
# match: destination.service.namespace != "kuda" && destination.service.namespace != "istio-system" && destination.service.namespace != "knative-serving" && destination.service.namespace != "kube-system" && destination.service.namespace != "cert-manager"
match: source.labels["istio"] == "ingressgateway" && destination.service.namespace != "kuda"
# match: source.labels["istio"] == "ingressgateway" && destination.service.namespace != "kuda"
match: match(source.labels["istio"], "nothing")
actions:
- handler: kuda-handler.istio-system
instances:
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: skaffold/v1
kind: Config
build:
artifacts:
- image: gcr.io/kuda-project/kuda-mixer-adapter
- image: gcr.io/kuda-cloud/kuda-mixer-adapter
docker:
dockerfile: ./Dockerfile
deploy:
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions images/deployer/Dockerfile → install/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ WORKDIR /go/src/github.com/cyrildiagne/kuda
RUN go mod download

COPY pkg ./pkg
WORKDIR /go/src/github.com/cyrildiagne/kuda/pkg/deployer
WORKDIR /go/src/github.com/cyrildiagne/kuda/pkg/deploy
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux go build -installsuffix cgo -o deployer .

#
Expand Down Expand Up @@ -50,7 +50,7 @@ RUN chmod +x /usr/local/bin/kubectl
COPY --from=builder /tmp/skaffold /usr/local/bin/skaffold
RUN chmod +x /usr/local/bin/skaffold

COPY --from=builder /go/src/github.com/cyrildiagne/kuda/pkg/deployer/deployer /root/
COPY --from=builder /go/src/github.com/cyrildiagne/kuda/pkg/deploy/deployer /root/
RUN chmod +x /root/deployer

# Launch the app on port 80.
Expand Down
4 changes: 2 additions & 2 deletions images/deployer/README.md → install/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

```bash
docker build \
-t gcr.io/kuda-project/deployer \
-t gcr.io/kuda-cloud/deployer \
-f images/deployer/Dockerfile \
.
```
Expand All @@ -16,7 +16,7 @@ docker run --rm \
-v `dirname $GOOGLE_APPLICATION_CREDENTIALS`:/credentials \
-e PORT=80 \
-p 8080:80 \
gcr.io/kuda-project/deployer
gcr.io/kuda-cloud/deployer
```

## Deploy
Expand Down
Loading

0 comments on commit 1e69ecd

Please sign in to comment.