Expose TCP services using ingress-nginx

A no nonsense guide to exposing TCP services using ingress-nginx.

Install the TCP service

Install the Service that binds the TCP port you need to expose.

For this example we'll install a dind (Docker in Docker) deployment and expose TCP port 2376.

helm repo add lazybit https://chartmuseum.lazybit.ch
helm repo update
helm install dind lazybit/dind --set extraHosts[0]=example.com

Note: Set extraHosts to the DNS name that will resolve the service.

Note: Check this StackOverflow answer for an example exposing a PostgresQL database.

Install ingress-nginx

Install the ingress-nginx contoller for your cluster.

Create the tcp-services ConfigMap

The tcp-services ConfigMap's data entries are formatted: <external port>: <namespace/service name>:<service port>:[PROXY]:[PROXY]

cat <<EOF |kubectl apply -n ingress-nginx -f -
apiVersion: v1
data:
  "2376": default/dind:2376
kind: ConfigMap
metadata:
  name: tcp-services
EOF

Patch the ingress-controller Deployment

Patch the ingress-nginx Deployment's spec.template.spec.containers[0].args with the --tcp-services argument using the format --tcp-services=<namespace/configmap name>:

INGRESS_NGINX_ARGS=$(\
    kubectl get deployments.apps \
    -n ingress-nginx \
    nginx-ingress-controller \
    -o json | jq '.spec.template.spec.containers[]|select(.name=="nginx-ingress-controller")|.args+=["--tcp-services=ingress-nginx/tcp-services"]|.args|unique'
)
PATCH='{"spec":{"template":{"spec":{"containers":[{"name":"nginx-ingress-controller","args":[{}]}]}}}}'
kubectl patch deployments.apps -n ingress-nginx nginx-ingress-controller -p "$(echo "$PATCH" |jq ".spec.template.spec.containers[0].args=$INGRESS_NGINX_ARGS")"

Patch the ingress-nginx Service

Patch the ingress-nginx Service:

kubectl patch service -n ingress-nginx ingress-nginx -p '{"spec": {"ports": [{"port": 2376,"targetPort": 2376,"name": "dind"}]}}'

Tip: Google Kubernetes Engine and DigitalOcean will automatically update existing firewall rules for allowing traffic on the specified port.

Test the connection

Copy the client TLS certificates for connecting to the docker daemon:

kubectl cp dind-0:/certs/client client

Set the users environment and connect to the remote docker daemon:

export DOCKER_HOST=tcp://example.com:2376
export DOCKER_CERT_PATH=${PWD}/client
export DOCKER_TLS_VERIFY=1
docker ps