Installing PFS on Docker Desktop

This topic describes how to install Pivotal Function Service (PFS) on a development machine using Docker Desktop for macOS or Windows.

Requirements

  • Docker Desktop for Mac or Windows has been installed at version 2.1.0.1 or later. The kubectl CLI is included with Docker Desktop.
  • The pfs CLI has been downloaded and installed.
  • The duffle CNAB runtime CLI has been downloaded and installed.
  • The PFS thick bundle has been downloaded. Container images from the bundle will be pushed to the local registry running in docker.

Install a local Registry

Since PFS installations require a container registry, these instructions include running a local registry accessible from Kubernetes as well as from the host development machine at registry.pfs.svc.cluster.local:5000.

  1. Use the docker CLI to run the registry:2 container from Docker, listening on port 5000, and persisting images in the ~/.registry/storage directory.

    docker run -d -p 5000:5000 --restart=always --volume ~/.registry/storage:/var/lib/registry registry:2
    

    In Windows PowerShell (after enabling Shared Drives for drive C: in your Docker settings)

    docker run -d -p 5000:5000 --restart=always --volume c:/Users/$env:UserName/.registry/storage:/var/lib/registry registry:2
    
  2. Edit the /etc/hosts file on your development machine, adding the name registry.pfs.svc.cluster.local on the same line as the entry for localhost. On macOS the file should look something like this.

    ##
    127.0.0.1       localhost registry.pfs.svc.cluster.local
    255.255.255.255 broadcasthost
    ::1             localhost
    

    In Windows PowerShell running as Administrator

    Add-Content `
      -Path c:\Windows\System32\Drivers\etc\hosts `
      -Value '127.0.0.1 registry.pfs.svc.cluster.local'
    
  3. Validate that the registry is running.

    docker ps
    
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    02ea46d51f58        registry:2          "/entrypoint.sh /etc…"   About an hour ago   Up About a minute   0.0.0.0:5000->5000/tcp   sharp_pike
    
  4. Validate that the registry at registry.pfs.svc.cluster.local:5000 is reachable from your development machine.

    curl registry.pfs.svc.cluster.local:5000/v2/_catalog
    
    {"repositories":[]}
    
  5. Configure the docker daemon with an insecure registy at registry.pfs.svc.cluster.local:5000. E.g. in ~/.docker/daemon.json

    {
    "debug": true,
    "experimental": false,
    "insecure-registries": [
        "registry.pfs.svc.cluster.local:5000"
    ]
    }
    
  6. Follow the instructions to Push relocated images to the local registry, making sure that the images are relocated to registry.pfs.svc.cluster.local:5000.

Enable Kubernetes

Once Docker is installed and running, open Preferences in the Docker menu (Settings in Windows).

  • In the Advanced section configure your VM with 4GB of memory and 4 CPUs.
  • In the Kubernetes section, enable Kubernetes, click Apply, and wait for the Kubernetes cluster to start running.
  • Use the Docker menu or run kubectl config current-context to verify that the context is set to docker-desktop. If necessary set the current context with kubectl config use-context docker-desktop.

In a separate terminal window, watch the pods in the cluster.

watch kubectl get pod --all-namespaces
NAMESPACE     NAME                                     READY   STATUS    RESTARTS   AGE
docker        compose-6b69ff6b9d-2lc7r                 1/1     Running   0          13s
docker        compose-api-6c5bf98cc7-gfc4v             1/1     Running   0          13s
kube-system   coredns-fb8b8dccf-mwwwt                  1/1     Running   0          90s
kube-system   coredns-fb8b8dccf-sjhxk                  1/1     Running   0          90s
kube-system   etcd-docker-desktop                      1/1     Running   0          32s
kube-system   kube-apiserver-docker-desktop            1/1     Running   0          13s
kube-system   kube-controller-manager-docker-desktop   1/1     Running   0          39s
kube-system   kube-proxy-rmgb9                         1/1     Running   0          90s
kube-system   kube-scheduler-docker-desktop            1/1     Running   0          21s

Configure the registry in Kubernetes

Create an externalname kubernetes service called registry in the pfs namespace. Using the external name host.docker.internal will result in registry.pfs.svc.cluster.local resolving to the host machine, allowing container builds running in the cluster, to work with the local registry.

kubectl create namespace pfs
kubectl create service externalname registry -n pfs --external-name=host.docker.internal --tcp=5000:5000

Configure duffle

Set the environment variables required by the duffle Kubernetes driver, create a namespace for duffle, create a service account for duffle and give it cluster-admin permissions.

export SERVICE_ACCOUNT=duffle-runtime
export KUBE_NAMESPACE=duffle
kubectl create namespace $KUBE_NAMESPACE
kubectl create serviceaccount "${SERVICE_ACCOUNT}" -n "${KUBE_NAMESPACE}"
kubectl create clusterrolebinding "${SERVICE_ACCOUNT}-cluster-admin" --clusterrole cluster-admin --serviceaccount "${KUBE_NAMESPACE}:${SERVICE_ACCOUNT}"

Install PFS

Change to the directory with the downloaded PFS thick bundle and run duffle install with the relocation mapping file created during image relocation.

duffle install my-pfs pfs-bundle-thick.tgz --bundle-is-file \
--relocation-mapping pfs-relmap.json \
--driver k8s \
--set node_port=true

The --node-port option is required for access to Kubernetes services via NodePort rather than LoadBalancer.

Watch for all the pods to start running.

NAMESPACE         NAME                                      READY   STATUS    RESTARTS   AGE
docker            compose-6c67d745f6-rdgnn                  1/1     Running   1          29m
docker            compose-api-57ff65b8c7-ptx45              1/1     Running   1          29m
istio-system      cluster-local-gateway-79488cf4d4-cxtcn    1/1     Running   0          80s
istio-system      istio-ingressgateway-7dd7c78b6b-ddznz     2/2     Running   0          80s
istio-system      istio-pilot-864f8bb559-qzz72              1/1     Running   0          80s
knative-build     build-controller-7cb488654c-97ps8         1/1     Running   0          80s
knative-build     build-webhook-6d44665d7c-qdmcf            1/1     Running   0          80s
knative-serving   activator-574f6c964d-nfcpc                1/1     Running   0          77s
knative-serving   autoscaler-5f4fc6ffb9-kh4tx               1/1     Running   0          77s
knative-serving   controller-6c96bf4dfd-jcjc4               1/1     Running   0          77s
knative-serving   networking-certmanager-65db98c9f6-p8hdx   1/1     Running   0          77s
knative-serving   networking-istio-7c596dff5f-99zwx         1/1     Running   0          77s
knative-serving   webhook-78f56b7695-jnwtn                  1/1     Running   0          77s
kube-system       coredns-584795fc57-pp44c                  1/1     Running   1          30m
kube-system       coredns-584795fc57-zdmb5                  1/1     Running   1          30m
kube-system       etcd-docker-desktop                       1/1     Running   1          29m
kube-system       kube-apiserver-docker-desktop             1/1     Running   1          29m
kube-system       kube-controller-manager-docker-desktop    1/1     Running   1          29m
kube-system       kube-proxy-4b68z                          1/1     Running   1          30m
kube-system       kube-scheduler-docker-desktop             1/1     Running   1          29m
riff-system       controller-79d7dfb4df-sv4qh               1/1     Running   0          57s
riff-system       webhook-59bb6b499-82bjk                   1/1     Running   0          56s

PFS is now installed.

Configure PFS to use your registry.

The pfs credential apply command will prompt for a password for the registry-user assuming basic authentication. In this case you can simply hit return, since the local registry is unauthenticated.

export REGISTRY=registry.pfs.svc.cluster.local:5000
export REGISTRY_USER=testuser

pfs credential apply my-pfs \
  --registry $REGISTRY \
  --registry-user $REGISTRY_USER \
  --default-image-prefix $REGISTRY/$REGISTRY_USER

You can now create your first function.