<p>I would like to expose my Kubernetes Managed Digital Ocean (single node) cluster's service on port 80 without the use of Digital Ocean's load balancer. Is this possible? How would I do this? </p>

<p>This is essentially a hobby project (I am beginning with Kubernetes) and just want to keep the cost very low. </p>

<p>You can deploy an Ingress configured to use the host network and port 80/443.</p>
<ol>
<li><p>DO's firewall for your cluster doesn't have 80/443 inbound open by default.</p>
<p>If you edit the auto-created firewall the rules <a href="https://www.digitalocean.com/community/questions/how-to-customize-firewall-rules-for-managed-kubernetes-service" rel="noreferrer">will eventually reset themselves</a>. The solution is to create a separate firewall also pointing at the same Kubernetes worker nodes:</p>
</li>
</ol>
<pre><code>$ doctl compute firewall create \
--inbound-rules=&quot;protocol:tcp,ports:80,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:443,address:0.0.0.0/0,address:::/0&quot; \
--tag-names=k8s:CLUSTER_UUID \
--name=k8s-extra-mycluster
</code></pre>
<p>(Get the <code>CLUSTER_UUID</code> value from the dashboard or the ID column from <code>doctl kubernetes cluster list</code>)</p>
<ol start="2">
<li>Create the <a href="https://kubernetes.github.io/ingress-nginx/" rel="noreferrer">nginx ingress</a> using the host network. I've included the <a href="https://github.com/helm/charts/tree/master/stable/nginx-ingress" rel="noreferrer">helm chart</a> config below, but you could do it via the direct install process too.</li>
</ol>
<p>EDIT: The Helm chart in the above link has been DEPRECATED, Therefore the correct way of installing the chart would be(<a href="https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx" rel="noreferrer">as per the new docs</a>) is :</p>
<pre><code>helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
</code></pre>
<p>After this repo is added &amp; updated</p>
<pre><code># For Helm 2
$ helm install stable/nginx-ingress --name=myingress -f myingress.values.yml

# For Helm 3
$ helm install myingress stable/nginx-ingress -f myingress.values.yml

#EDIT: The New way to install in helm 3
helm install myingress ingress-nginx/ingress-nginx -f myingress.values.yaml
</code></pre>
<p><code>myingress.values.yml</code> for the chart:</p>
<pre class="lang-yaml prettyprint-override"><code>---
controller:
  kind: DaemonSet
  hostNetwork: true
  dnsPolicy: ClusterFirstWithHostNet
  daemonset:
    useHostPort: true
  service:
    type: ClusterIP
rbac:
  create: true
</code></pre>
<ol start="3">
<li><p>you should be able to access the cluster on :80 and :443 via any worker node IP and it'll route traffic to your ingress.</p>
</li>
<li><p>since node IPs can &amp; do change, look at deploying <a href="https://github.com/kubernetes-incubator/external-dns" rel="noreferrer">external-dns</a> to manage DNS entries to point to your worker nodes. Again, using the helm chart and assuming your DNS domain is hosted by DigitalOcean (though any supported DNS provider will work):</p>
</li>
</ol>
<pre><code># For Helm 2
$ helm install --name=mydns -f mydns.values.yml stable/external-dns

# For Helm 3
$ helm install mydns stable/external-dns -f mydns.values.yml
</code></pre>
<p><code>mydns.values.yml</code> for the chart:</p>
<pre class="lang-yaml prettyprint-override"><code>---
provider: digitalocean
digitalocean:
  # create the API token at https://cloud.digitalocean.com/account/api/tokens
  # needs read + write
  apiToken: &quot;DIGITALOCEAN_API_TOKEN&quot;
domainFilters:
  # domains you want external-dns to be able to edit
  - example.com
rbac:
  create: true
</code></pre>
<ol start="5">
<li>create a Kubernetes <a href="https://kubernetes.github.io/ingress-nginx/user-guide/basic-usage/" rel="noreferrer">Ingress resource</a> to route requests to an existing Kubernetes service:</li>
</ol>
<pre class="lang-yaml prettyprint-override"><code>---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: testing123-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: testing123.example.com             # the domain you want associated
      http:
        paths:
          - path: /
            backend:
              serviceName: testing123-service  # existing service
              servicePort: 8000                # existing service port
</code></pre>
<ol start="6">
<li>after a minute or so you should see the DNS records appear and be resolvable:</li>
</ol>
<pre><code>$ dig testing123.example.com             # should return worker IP address
$ curl -v http://testing123.example.com  # should send the request through the Ingress to your backend service
</code></pre>
<p>(Edit: editing the automatically created firewall rules eventually breaks, add a separate firewall instead).</p>
