|
| 1 | +--- |
| 2 | +title: "Use a custom NGINX ingress controller and configure HTTPS" |
| 3 | +services: azure-dev-spaces |
| 4 | +ms.date: "12/10/2019" |
| 5 | +ms.topic: "conceptual" |
| 6 | +description: "Learn how to configure Azure Dev Spaces to use a custom NGINX ingress controller and configure HTTPS using that ingress controller" |
| 7 | +keywords: "Docker, Kubernetes, Azure, AKS, Azure Kubernetes Service, containers, Helm, service mesh, service mesh routing, kubectl, k8s" |
| 8 | +--- |
| 9 | + |
| 10 | +# Use a custom NGINX ingress controller and configure HTTPS |
| 11 | + |
| 12 | +This article shows you how to configure Azure Dev Spaces to use a custom NGINX ingress controller. This article also shows you how to configure that custom ingress controller to use HTTPS. |
| 13 | + |
| 14 | +## Prerequisites |
| 15 | + |
| 16 | +* An Azure subscription. If you don't have one, you can create a [free account][azure-account-create]. |
| 17 | +* [Azure CLI installed][az-cli]. |
| 18 | +* [Azure Kubernetes Service (AKS) cluster with Azure Dev Spaces enabled][qs-cli]. |
| 19 | +* [kubectl][kubectl] installed. |
| 20 | +* [Helm 3 installed][helm-installed]. |
| 21 | +* [A custom domain][custom-domain] with a [DNS Zone][dns-zone] in the same resource group as your AKS cluster. |
| 22 | + |
| 23 | +## Configure a custom NGINX ingress controller |
| 24 | + |
| 25 | +Connect to your cluster using [kubectl][kubectl], the Kubernetes command-line client. To configure `kubectl` to connect to your Kubernetes cluster, use the [az aks get-credentials][az-aks-get-credentials] command. This command downloads credentials and configures the Kubernetes CLI to use them. |
| 26 | + |
| 27 | +```azurecli-interactive |
| 28 | +az aks get-credentials --resource-group myResourceGroup --name myAKS |
| 29 | +``` |
| 30 | + |
| 31 | +To verify the connection to your cluster, use the [kubectl get][kubectl-get] command to return a list of the cluster nodes. |
| 32 | + |
| 33 | +```console |
| 34 | +$ kubectl get nodes |
| 35 | +NAME STATUS ROLES AGE VERSION |
| 36 | +aks-nodepool1-12345678-vmssfedcba Ready agent 13m v1.14.1 |
| 37 | +``` |
| 38 | + |
| 39 | +Add the [official stable Helm repository][helm-stable-repo], which contains the NGINX ingress controller Helm chart. |
| 40 | + |
| 41 | +```console |
| 42 | +helm repo add stable https://kubernetes-charts.storage.googleapis.com/ |
| 43 | +``` |
| 44 | + |
| 45 | +Create a Kubernetes namespace for the NGINX ingress controller and install it using `helm`. |
| 46 | + |
| 47 | +```console |
| 48 | +kubectl create ns nginx |
| 49 | +helm install nginx stable/nginx-ingress --namespace nginx |
| 50 | +``` |
| 51 | + |
| 52 | +Get the IP address of the NGINX ingress controller service using [kubectl get][kubectl-get]. |
| 53 | + |
| 54 | +```console |
| 55 | +kubectl get svc -n nginx --watch |
| 56 | +``` |
| 57 | + |
| 58 | +The sample output shows the IP addresses for all the services in the *nginx* name space. |
| 59 | + |
| 60 | +```console |
| 61 | +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 62 | +nginx-nginx-ingress-controller LoadBalancer 10.0.19.39 <pending> 80:31314/TCP,443:30521/TCP 10s |
| 63 | +nginx-nginx-ingress-default-backend ClusterIP 10.0.210.231 <none> 80/TCP 10s |
| 64 | +... |
| 65 | +nginx-nginx-ingress-controller LoadBalancer 10.0.19.39 MY_EXTERNAL_IP 80:31314/TCP,443:30521/TCP 26s |
| 66 | +``` |
| 67 | + |
| 68 | +Add an *A* record to your DNS zone with the external IP address of the NGINX service using [az network dns record-set a add-record][az-network-dns-record-set-a-add-record]. |
| 69 | + |
| 70 | +```console |
| 71 | +az network dns record-set a add-record \ |
| 72 | + --resource-group myResourceGroup \ |
| 73 | + --zone-name MY_CUSTOM_DOMAIN \ |
| 74 | + --record-set-name *.nginx \ |
| 75 | + --ipv4-address MY_EXTERNAL_IP |
| 76 | +``` |
| 77 | + |
| 78 | +The above example adds an *A* record to the *MY_CUSTOM_DOMAIN* DNS zone. |
| 79 | + |
| 80 | +In this article, you use the [Azure Dev Spaces Bike Sharing sample application](https://github.com/Azure/dev-spaces/tree/master/samples/BikeSharingApp) to demonstrate using Azure Dev Spaces. Clone the application from GitHub and navigate into its directory: |
| 81 | + |
| 82 | +```cmd |
| 83 | +git clone https://github.com/Azure/dev-spaces |
| 84 | +cd dev-spaces/samples/BikeSharingApp/charts |
| 85 | +``` |
| 86 | + |
| 87 | +Open [values.yaml][values-yaml] and replace all instances of *<REPLACE_ME_WITH_HOST_SUFFIX>* with *nginx.MY_CUSTOM_DOMAIN* using your domain for *MY_CUSTOM_DOMAIN*. Also replace *kubernetes.io/ingress.class: nginx-azds # Dev Spaces-specific* with *kubernetes.io/ingress.class: nginx # Custom Ingress*. Below is an example of an updated `values.yaml` file: |
| 88 | + |
| 89 | +```yaml |
| 90 | +# This is a YAML-formatted file. |
| 91 | +# Declare variables to be passed into your templates. |
| 92 | + |
| 93 | +bikesharingweb: |
| 94 | + ingress: |
| 95 | + annotations: |
| 96 | + kubernetes.io/ingress.class: nginx # Custom Ingress |
| 97 | + hosts: |
| 98 | + - dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN # Assumes deployment to the 'dev' space |
| 99 | + |
| 100 | +gateway: |
| 101 | + ingress: |
| 102 | + annotations: |
| 103 | + kubernetes.io/ingress.class: nginx # Custom Ingress |
| 104 | + hosts: |
| 105 | + - dev.gateway.nginx.MY_CUSTOM_DOMAIN # Assumes deployment to the 'dev' space |
| 106 | +``` |
| 107 | +
|
| 108 | +Save your changes and close the file. |
| 109 | +
|
| 110 | +Create the *dev* space with your sample application using `azds space select`. |
| 111 | + |
| 112 | +```console |
| 113 | +azds space select -n dev -y |
| 114 | +``` |
| 115 | + |
| 116 | +Deploy the sample application using `helm install`. |
| 117 | + |
| 118 | +```console |
| 119 | +helm install bikesharing . --dependency-update --namespace dev --atomic |
| 120 | +``` |
| 121 | + |
| 122 | +The above example deploys the sample application to the *dev* namespace. |
| 123 | + |
| 124 | +Display the URLs to access the sample application using `azds list-uris`. |
| 125 | + |
| 126 | +```console |
| 127 | +azds list-uris |
| 128 | +``` |
| 129 | + |
| 130 | +The below output shows the example URLs from `azds list-uris`. |
| 131 | + |
| 132 | +```console |
| 133 | +Uri Status |
| 134 | +--------------------------------------------------- --------- |
| 135 | +http://dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN/ Available |
| 136 | +http://dev.gateway.nginx.MY_CUSTOM_DOMAIN/ Available |
| 137 | +``` |
| 138 | + |
| 139 | +Navigate to the *bikesharingweb* service by opening the public URL from the `azds list-uris` command. In the above example, the public URL for the *bikesharingweb* service is `http://dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN/`. |
| 140 | + |
| 141 | +Use the `azds space select` command to create a child space under *dev* and list the URLs to access the child dev space. |
| 142 | + |
| 143 | +```console |
| 144 | +azds space select -n dev/azureuser1 -y |
| 145 | +azds list-uris |
| 146 | +``` |
| 147 | + |
| 148 | +The below output shows the example URLs from `azds list-uris` to access the sample application in the *azureuser1* child dev space. |
| 149 | + |
| 150 | +```console |
| 151 | +Uri Status |
| 152 | +--------------------------------------------------- --------- |
| 153 | +http://azureuser1.s.dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN/ Available |
| 154 | +http://azureuser1.s.dev.gateway.nginx.MY_CUSTOM_DOMAIN/ Available |
| 155 | +``` |
| 156 | + |
| 157 | +Navigate to the *bikesharingweb* service in the *azureuser1* child dev space by opening the public URL from the `azds list-uris` command. In the above example, the public URL for the *bikesharingweb* service in the *azureuser1* child dev space is `http://azureuser1.s.dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN/`. |
| 158 | + |
| 159 | +## Configure the NGINX ingress controller to use HTTPS |
| 160 | + |
| 161 | +Use [cert-manager][cert-manager] to automate the management of the TLS certificate when configuring your NGINX ingress controller to use HTTPS. Use `helm` to install the *certmanager* chart. |
| 162 | + |
| 163 | +```console |
| 164 | +kubectl apply --validate=false -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.12/deploy/manifests/00-crds.yaml --namespace nginx |
| 165 | +kubectl label namespace nginx certmanager.k8s.io/disable-validation=true |
| 166 | +helm repo add jetstack https://charts.jetstack.io |
| 167 | +helm repo update |
| 168 | +helm install cert-manager --namespace nginx --version v0.12.0 jetstack/cert-manager --set ingressShim.defaultIssuerName=letsencrypt --set ingressShim.defaultIssuerKind=ClusterIssuer |
| 169 | +``` |
| 170 | + |
| 171 | +Create a `letsencrypt-clusterissuer.yaml` file and update the email field with your email address. |
| 172 | + |
| 173 | +```yaml |
| 174 | +apiVersion: cert-manager.io/v1alpha2 |
| 175 | +kind: ClusterIssuer |
| 176 | +metadata: |
| 177 | + name: letsencrypt |
| 178 | +spec: |
| 179 | + acme: |
| 180 | + server: https://acme-v02.api.letsencrypt.org/directory |
| 181 | + email: MY_EMAIL_ADDRESS |
| 182 | + privateKeySecretRef: |
| 183 | + name: letsencrypt |
| 184 | + solvers: |
| 185 | + - http01: |
| 186 | + ingress: |
| 187 | + class: nginx |
| 188 | +``` |
| 189 | + |
| 190 | +> [!NOTE] |
| 191 | +> For testing, there is also a [staging server][letsencrypt-staging-issuer] you can use for your *ClusterIssuer*. |
| 192 | + |
| 193 | +Use `kubectl` to apply `letsencrypt-clusterissuer.yaml`. |
| 194 | + |
| 195 | +```console |
| 196 | +kubectl apply -f letsencrypt-clusterissuer.yaml --namespace nginx |
| 197 | +``` |
| 198 | + |
| 199 | +Update [values.yaml][values-yaml] to include the details for using *cert-manager* and HTTPS. Below is an example of an updated `values.yaml` file: |
| 200 | + |
| 201 | +```yaml |
| 202 | +# This is a YAML-formatted file. |
| 203 | +# Declare variables to be passed into your templates. |
| 204 | +
|
| 205 | +bikesharingweb: |
| 206 | + ingress: |
| 207 | + annotations: |
| 208 | + kubernetes.io/ingress.class: nginx # Custom Ingress |
| 209 | + cert-manager.io/cluster-issuer: letsencrypt |
| 210 | + hosts: |
| 211 | + - dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN # Assumes deployment to the 'dev' space |
| 212 | + tls: |
| 213 | + - hosts: |
| 214 | + - dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN |
| 215 | + secretName: dev-bikesharingweb-secret |
| 216 | +
|
| 217 | +gateway: |
| 218 | + ingress: |
| 219 | + annotations: |
| 220 | + kubernetes.io/ingress.class: nginx # Custom Ingress |
| 221 | + cert-manager.io/cluster-issuer: letsencrypt |
| 222 | + hosts: |
| 223 | + - dev.gateway.nginx.MY_CUSTOM_DOMAIN # Assumes deployment to the 'dev' space |
| 224 | + tls: |
| 225 | + - hosts: |
| 226 | + - dev.gateway.nginx.MY_CUSTOM_DOMAIN |
| 227 | + secretName: dev-gateway-secret |
| 228 | +``` |
| 229 | + |
| 230 | +Upgrade the sample application using `helm`: |
| 231 | + |
| 232 | +```console |
| 233 | +helm upgrade bikesharing . --namespace dev --atomic |
| 234 | +``` |
| 235 | + |
| 236 | +Navigate to the sample application in the *dev/azureuser1* child space and notice you are redirected to use HTTPS. Also notice that the page loads, but the browser shows some errors. Opening the browser console shows the error relates to an HTTPS page trying to load HTTP resources. For example: |
| 237 | + |
| 238 | +```console |
| 239 | +Mixed Content: The page at 'https://azureuser1.s.dev.bikesharingweb.nginx.MY_CUSTOM_DOMAIN/devsignin' was loaded over HTTPS, but requested an insecure resource 'http://azureuser1.s.dev.gateway.nginx.MY_CUSTOM_DOMAIN/api/user/allUsers'. This request has been blocked; the content must be served over HTTPS. |
| 240 | +``` |
| 241 | + |
| 242 | +To fix this error, update [BikeSharingWeb/azds.yaml][azds-yaml] similar to the below: |
| 243 | + |
| 244 | +```yaml |
| 245 | +... |
| 246 | + ingress: |
| 247 | + annotations: |
| 248 | + kubernetes.io/ingress.class: nginx |
| 249 | + cert-manager.io/cluster-issuer: letsencrypt |
| 250 | + hosts: |
| 251 | + # This expands to [space.s.][rootSpace.]bikesharingweb.<random suffix>.<region>.azds.io |
| 252 | + - $(spacePrefix)$(rootSpacePrefix)bikesharingweb.nginx.MY_CUSTOM_DOMAIN |
| 253 | + tls: |
| 254 | + - hosts: |
| 255 | + - $(spacePrefix)$(rootSpacePrefix)bikesharingweb.nginx.MY_CUSTOM_DOMAIN |
| 256 | + secretName: dev-bikesharingweb-secret |
| 257 | +... |
| 258 | +``` |
| 259 | + |
| 260 | +Update [BikeSharingWeb/package.json][package-json] with a dependency for the *url* package. |
| 261 | + |
| 262 | +```json |
| 263 | +{ |
| 264 | +... |
| 265 | + "react-responsive": "^6.0.1", |
| 266 | + "universal-cookie": "^3.0.7", |
| 267 | + "url": "0.11.0" |
| 268 | + }, |
| 269 | +... |
| 270 | +``` |
| 271 | + |
| 272 | +Update the *getApiHostAsync* method in [BikeSharingWeb/pages/helpers.js][helpers-js] to use HTTPS: |
| 273 | + |
| 274 | +```javascript |
| 275 | +... |
| 276 | + getApiHostAsync: async function() { |
| 277 | + const apiRequest = await fetch('/api/host'); |
| 278 | + const data = await apiRequest.json(); |
| 279 | + |
| 280 | + var urlapi = require('url'); |
| 281 | + var url = urlapi.parse(data.apiHost); |
| 282 | +
|
| 283 | + console.log('apiHost: ' + "https://"+url.host); |
| 284 | + return "https://"+url.host; |
| 285 | + }, |
| 286 | +... |
| 287 | +``` |
| 288 | + |
| 289 | +Navigate to the `BikeSharingWeb` directory and use `azds up` to run your updated *BikeSharingWeb* service. |
| 290 | + |
| 291 | +```console |
| 292 | +cd ../BikeSharingWeb/ |
| 293 | +azds up |
| 294 | +``` |
| 295 | + |
| 296 | +Navigate to the sample application in the *dev/azureuser1* child space and notice you are redirected to use HTTPS without any errors. |
| 297 | + |
| 298 | +## Next steps |
| 299 | + |
| 300 | +Learn how Azure Dev Spaces helps you develop more complex applications across multiple containers, and how you can simplify collaborative development by working with different versions or branches of your code in different spaces. |
| 301 | + |
| 302 | +> [!div class="nextstepaction"] |
| 303 | +> [Team development in Azure Dev Spaces][team-development-qs] |
| 304 | + |
| 305 | + |
| 306 | +[az-cli]: /cli/azure/install-azure-cli?view=azure-cli-latest |
| 307 | +[az-aks-get-credentials]: /cli/azure/aks?view=azure-cli-latest#az-aks-get-credentials |
| 308 | +[az-network-dns-record-set-a-add-record]: /cli/azure/network/dns/record-set/a?view=azure-cli-latest#az-network-dns-record-set-a-add-record |
| 309 | +[custom-domain]: ../../app-service/manage-custom-dns-buy-domain.md#buy-the-domain |
| 310 | +[dns-zone]: ../../dns/dns-getstarted-cli.md |
| 311 | +[qs-cli]: ../quickstart-cli.md |
| 312 | +[team-development-qs]: ../quickstart-team-development.md |
| 313 | + |
| 314 | +[azds-yaml]: https://github.com/Azure/dev-spaces/blob/master/samples/BikeSharingApp/BikeSharingWeb/azds.yaml |
| 315 | +[azure-account-create]: https://azure.microsoft.com/free |
| 316 | +[cert-manager]: https://cert-manager.io/ |
| 317 | +[helm-installed]: https://helm.sh/docs/intro/install/ |
| 318 | +[helm-stable-repo]: https://helm.sh/docs/intro/quickstart/#initialize-a-helm-chart-repository |
| 319 | +[helpers-js]: https://github.com/Azure/dev-spaces/blob/master/samples/BikeSharingApp/BikeSharingWeb/pages/helpers.js#L7 |
| 320 | +[kubectl]: https://kubernetes.io/docs/user-guide/kubectl/ |
| 321 | +[kubectl-get]: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#get |
| 322 | +[letsencrypt-staging-issuer]: https://cert-manager.io/docs/configuration/acme/#creating-a-basic-acme-issuer |
| 323 | +[package-json]: https://github.com/Azure/dev-spaces/blob/master/samples/BikeSharingApp/BikeSharingWeb/package.json |
| 324 | +[values-yaml]: https://github.com/Azure/dev-spaces/blob/master/samples/BikeSharingApp/charts/values.yaml |
0 commit comments