title: How can I access a local FastAPI service with deployed with Skaffold?
body: <p>Until now I developed Python applications locally using docker and docker-compose. Now I'd like to change my development workflow to use <code>skaffold</code> with <code>docker</code> as builder, with <code>kubectl</code> as deployer and with <code>minikube</code> for managing the local kubernetes cluster.</p>
  <p>Let's say I've this docker based hello world for FastAPI:</p>
  <p>project structure:</p>
  <pre><code>app/app.py
  Dockerfile
  </code></pre>
  <p>app/app.py</p>
  <pre><code>from typing import Optional
  
  from fastapi import FastAPI
  
  app = FastAPI()
  
  
  @app.get(&quot;/&quot;)
  def read_root():
      return {&quot;Hello&quot;: &quot;World&quot;}
  
  @app.get(&quot;/items/{item_id}&quot;)
  def read_item(item_id: int, q: Optional[str] = None):
      return {&quot;item_id&quot;: item_id, &quot;q&quot;: q}
  </code></pre>
  <p>Dockerfile:</p>
  <pre><code>FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
  
  COPY ./app /app
  </code></pre>
  <p>If I run <code>docker build -t hello-fastapi .</code> and <code>docker run -p 80:80 hello-fastapi</code> I can access the service via <code>0.0.0.0</code> or <code>localhost</code>. I skip the <code>docker-compose</code> things here cause it does not matter w.r.t. the skaffold setup.</p>
  <p>To use <code>skaffold</code> I have the exact same project structure and content but I added the skaffold + kubectl specific things (<code>skaffold.yaml</code>, <code>deployment.yaml</code>):</p>
  <p>project structure:</p>
  <pre><code>app/app.py
  k8s/deployment.yaml
  Dockerfile
  skaffold.yaml
  </code></pre>
  <p>k8s/deployment.yaml</p>
  <pre><code>apiVersion: v1
  kind: Service
  metadata:
    name: fastapi-service
    labels:
      app: fastapi-service
  spec:
    clusterIP: None
    ports:
      - port: 80
        name: fastapi-service
    selector:
      app: fastapi-service
  ---
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: fastapi-service
    labels:
      app: fastapi-service
  spec:
    replicas: 1
    selector:
      matchLabels:
        app: fastapi-service
    template:
      metadata:
        labels:
          app: fastapi-service
      spec:
        containers:
        - name: fastapi-service
          image: fastapi-service
          ports:
          - containerPort: 80
  </code></pre>
  <p>skaffold.yaml</p>
  <pre><code>apiVersion: skaffold/v2beta10
  kind: Config
  build:
    artifacts:
    - image: fastapi-image
  deploy:
    kubectl:
      manifests:
        - k8s/*
  </code></pre>
  <p>If I run <code>skaffold dev</code> everything seems to be fine:</p>
  <pre><code>Listing files to watch...
   - fastapi-service
  Generating tags...
   - fastapi-service -&gt; fastapi-service:latest
  Some taggers failed. Rerun with -vdebug for errors.
  Checking cache...
   - fastapi-service: Found Locally
  Tags used in deployment:
   - fastapi-service -&gt; fastapi-service:17659a877904d862184d7cc5966596d46b0765f1995f7abc958db4b3f98b8a35
  Starting deploy...
   - service/fastapi-service created
   - deployment.apps/fastapi-service created
  Waiting for deployments to stabilize...
   - deployment/fastapi-service is ready.
  Deployments stabilized in 2.165700782s
  Press Ctrl+C to exit
  Watching for changes...
  [fastapi-service] Checking for script in /app/prestart.sh
  [fastapi-service] Running script /app/prestart.sh
  [fastapi-service] Running inside /app/prestart.sh, you could add migrations to this file, e.g.:
  [fastapi-service] 
  [fastapi-service] #! /usr/bin/env bash
  [fastapi-service] 
  [fastapi-service] # Let the DB start
  [fastapi-service] sleep 10;
  [fastapi-service] # Run migrations
  [fastapi-service] alembic upgrade head
  [fastapi-service] 
  [fastapi-service] [2020-12-15 19:02:57 +0000] [1] [INFO] Starting gunicorn 20.0.4
  [fastapi-service] [2020-12-15 19:02:57 +0000] [1] [INFO] Listening at: http://0.0.0.0:80 (1)
  [fastapi-service] [2020-12-15 19:02:57 +0000] [1] [INFO] Using worker: uvicorn.workers.UvicornWorker
  [fastapi-service] [2020-12-15 19:02:57 +0000] [8] [INFO] Booting worker with pid: 8
  ...
  </code></pre>
  <p>However I cannot access the service via my web browser. How can I access the service from my local machine via e.g. the web browser?</p>
  <p><strong>EDIT</strong>:</p>
  <p>According to <code>minikube service list</code> the service <code>fastapi-service</code> exists:</p>
  <pre><code>|----------------------|---------------------------|--------------|-----|
  |      NAMESPACE       |           NAME            | TARGET PORT  | URL |
  |----------------------|---------------------------|--------------|-----|
  | default              | fastapi-service           | No node port |
  | default              | kubernetes                | No node port |
  | kube-system          | kube-dns                  | No node port |
  | kubernetes-dashboard | dashboard-metrics-scraper | No node port |
  | kubernetes-dashboard | kubernetes-dashboard      | No node port |
  |----------------------|---------------------------|--------------|-----|
  
  </code></pre>
  <p>But I cannot access it via <code>curl $(minikube service fastapi-service --url)</code>:</p>
  <pre><code>curl: (3) Failed to convert  to ACE; string contains a disallowed character
  
  curl: (6) Could not resolve host: service
  curl: (6) Could not resolve host: default
  curl: (6) Could not resolve host: has
  curl: (6) Could not resolve host: no
  curl: (6) Could not resolve host: node
  curl: (6) Could not resolve host: port
  </code></pre>
  <p>Probably this is related to <a href="https://stackoverflow.com/questions/60556096/unable-to-get-clusterip-service-url-from-minikube">Unable to get ClusterIP service url from minikube</a> . If I change <code>deployment.yaml</code> to</p>
  <pre><code>apiVersion: v1
  kind: Service
  metadata:
    name: fastapi-service
    labels:
      app: fastapi-service
  spec:
    type: NodePort
    ports:
      - targetPort: 80
        port: 80
    selector:
      app: fastapi-service
  ---
  apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: fastapi-service
    labels:
      app: fastapi-service
  spec:
    replicas: 1
    selector:
      matchLabels:
        app: fastapi-service
    template:
      metadata:
        labels:
          app: fastapi-service
      spec:
        containers:
        - name: fastapi-service
          image: fastapi-service
          ports:
          - containerPort: 80
  </code></pre>
  <p>accessing the service via <code>curl $(minikube service fastapi-service --url)</code> is successful:</p>
  <pre><code>{&quot;message&quot;:&quot;Hello world! From FastAPI running on Uvicorn with Gunicorn. Using Python 3.7&quot;}
  
  </code></pre>
  <p>However I cannot access the service via the web browser.</p>