9
votes

I'm running into an annoying issue where my containerized app runs fine locally, but fails when deployed to azure, despite the ports being exposed properly.

The details:

  • azure web app for container with Linux OS on a Basic B1 machine.
  • nodejs v12 LTS with express server listening on HTTPS port 443. Includes an HTTP 404 (Not Found) error handler.
  • database db Mongodb Atlas on M0 Sandbox (free tier). Local and Azure IPs whitelisted.
  • docker container using Dockerfile. no Kubernetes, no yml config file.
  • docker image hosted on private Docker Hub repo, pulled by azure on build

Running locally on Windows 10 x64:

In both cases I get the expected output from my nodejs app:

Running in production on x64
Express HTTPS server listening on port 443
mongo :: connected to database mydb at mydb-tot7b.azure.mongodb.net

(obvously, myapp and mydb are not the actual names. Used here for convenience.)

Running in azure:

Under Configuration -> Application settings:

PORT=443
WEBSITES_PORT=443
DOCKER_ENABLE_CI=true

Pipeline set up pulling docker image myrepo/myapp:latest from private Docker Hub repo on build. Image is pulled correctly. Fails via https://myapp.azurewebsites.net/ with error 503 Service Temporarily Unavailable.

Azure log:

2020-04-10 18:02:21.040 INFO  - Pulling image: myrepo/myapp:latest
2020-04-10 18:02:22.128 INFO  - latest Pulling from myrepo/myapp
2020-04-10 18:02:22.129 INFO  -  Digest: sha256:982[...]
2020-04-10 18:02:22.129 INFO  -  Status: Image is up to date for myrepo/myapp:latest
2020-04-10 18:02:22.131 INFO  - Pull Image successful, Time taken: 0 Minutes and 1 Seconds
2020-04-10 18:02:22.143 INFO  - Starting container for site
2020-04-10 18:02:22.144 INFO  - docker run -d -p 7909:443 --name myapp_0_138f197c -e PORT=80 -e WEBSITES_ENABLE_APP_SERVICE_STORAGE=false -e WEBSITES_PORT=443 -e WEBSITE_SITE_NAME=myapp -e WEBSITE_AUTH_ENABLED=False -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=myapp.azurewebsites.net -e WEBSITE_INSTANCE_ID=6fc3[...] myrepo/myapp:latest
2020-04-10 18:02:22.144 INFO  - Logging is not enabled for this container.Please use https://aka.ms/linux-diagnostics to enable logging to see container logs here.
2020-04-10 18:02:23.473 INFO  - Initiating warmup request to container myapp_0_138f197c for site myapp
2020-04-10 18:02:45.304 INFO  - Waiting for response to warmup request for container myapp_0_138f197c. Elapsed time = 21.8308149 sec
[...]
2020-04-10 18:06:08.252 INFO  - Waiting for response to warmup request for container myapp_0_138f197c. Elapsed time = 224.7791547 sec
2020-04-10T18:02:24.893958779Z Running in production on x64
2020-04-10T18:02:26.275376640Z Express HTTPS server listening on port 80
2020-04-10T18:02:26.601261213Z mongo :: connected to database mydb at mydb-tot7b.azure.mongodb.net
2020-04-10 18:06:14.346 ERROR - Container myapp_0_138f197c for site myapp did not start within expected time limit. Elapsed time = 230.8732099 sec
2020-04-10 18:06:14.365 ERROR - Container myapp_0_138f197c didn't respond to HTTP pings on port: 443, failing site start. See container logs for debugging.
2020-04-10 18:06:14.427 INFO  - Stoping site myapp because it failed during startup.

Why the containerized app seems to start correctly, as seen in the azure log, but the container fails to respond to HTTP ping on 443, which is exposed both in dockerfile and in azure with PORT and WEBSITES_PORT?
Do I need to make my HTTPS server explicitly respond to HTTP PING and if so, how do I do it?

Dockerfile:

FROM node:12

WORKDIR /usr/src/myapp

COPY package*.json ./

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

RUN npm install

COPY . .

EXPOSE 443
CMD [ "node", "app.js" ]

This issue might be considered a duplicate, but I provide a lot more relevant information, compared to most of the issues below. Also, I spent significant time in troubleshooting and none of these relevant resources seemed to help:

2
Kudos for a detailed and researched question! Can you explain why you want to use port 443 in your container? When enforcing https at the App Service level, TLS termination will happen and traffic will be routed to your container port, let's say port 80. Have you tried setting your container to port 80 to see if that works? Using another port need that WEBSITES_PORT setting to be set to your container port.CSharpRocks
Thanks, CSharpRocks. I use/expose port 443 in my dockerfile, because my nodejs app is listening on that port. I also tried to have my app listen on port 5000, expose that port in dockerfile instead, and have WEBSITES_PORT=5000, but I get the same result and error. What do you mean by setting my container to port 80? In my dockerfile I have to expose the same port that my app is listening on and I find it weird to listen on port 80 for an HTTPS connection.Mike
I mean don't use https inside the data centre. Let Azure handle the Internet connection using https, do the tls termination and connect to your container via http. That works for me. I understand that, it may not be possible for you to change your app or the container configuration, in that case my solution will not work for you.CSharpRocks
This worked indeed! I made my express app use http on port 8080 instead of https, exposed port 8080 inside the container and now I can access it via https://myapp.azurewebsites.net. As you said, Azure is handling the TLS termination, so my webpage is still using secure connection. Now I'm wondering whether this is a workaround or The Solution... What is the drawback of NOT having my app use https server? All other answers on similar questions focus on the port issue, but my issue was that I was insisting on using https server. Please post your input as an answer, so I can accept it.Mike
A common pattern is to let the infrastructure handle the TLS side and internally, not worry about that. That could be a drawback on multi tenant systems but for small apps, delegating this to the infrastructure keeps your apps and your deployments simpler.CSharpRocks

2 Answers

5
votes

When enforcing HTTPS at the App Service level, TLS termination will happen and traffic will be routed to your container port so there's no need to enforce TLS from your container.

If your container listens on another port (ex: 8081), simply set the WEBSITES_PORT application setting to that port number. App Service will listen on port 80 and forward traffic to your container port.

0
votes

My own app had been doing app.UseHttpsRedirection() in Startup.Configure. That was the cause of this error for me. As soon as I stopped doing that, the problem went away.