Closed MichaelMarkieta closed 7 years ago
Hi @MichaelMarkieta,
Can you expand on this a little bit?
If you are using the out-of-box Python scripts, this is a known issue. We don't yet have Python script templates for Linux, as we don't have a blessed Python image and we don't have python tools preinstalled in Kudu on Linux. This is on our radar for the future.
Hey @nickwalkmsft, I am looking for the ability to generate BASH
kuduscripts for Python application. Since the tooling only allows batch for now, its not possible to run them in the linux app services as you said. Glad its on the radar.
Do you think I can get around this by specifying a custom docker container that is loosely based on the NodeJS app services runtime stack container, and modifying the container and kuduscript to suit?
This could be made to work, but there are a couple things required, and one major caveat.
By all means, feel free to take a swing at it, but with no. 3 above, I wouldn't pursue it for anything more than a toy/sample app.
Python support is definitely on our radar, but we don't have an ETA for it at the moment.
@nickwalkmsft are the "platform images" for the other stacks publically available? I'd like to look at what the Dockerfile
(if it's a Dockerfile
) looks like.
Yes!
We are working on making the images friendlier for local testing and derivation.
@nickwalkmsft great! Thank you so much. One question:
The port number that your container exposes its HTTP services on doesn't matter as long as App Service knows which one it is. If you are running a custom container, the best thing to do is set the PORT appsetting of your App Service. This unambiguously indicates the port number of your application.
Also, EXPOSE is frequently misunderstood. EXPOSEing a port is not actually required to publish it on the host. You can try this locally with docker run: you can do -p \<hostport>:\<containerport> without putting EXPOSE \<containerport> in the Dockerfile and it will work just fine. EXPOSE is required if you want to expose a port on a container network without publishing it to the host. 2222 is exposed on our blessed images for some upcoming functionality we haven't talked much about yet.
I was wondering about that SSH stuff!
I think I have successfully been able to deploy a custom container but right now I am having issues with deploying my site. For some reason I am not able to set up local git pushing (via az appservice web source-control config-local-git --name *** --resource-group *** --query url --output tsv
). Getting The requested URL returned error: 400
error when I try to push. Trying to set up deployment options through Bitbucket webhooks also fails (the webhook is created in Bitbucket but Azure reports an error). At this point, I am not sure if it's me or Azure with problems!
I can confirm the docker image successfully downloads and the container starts by browsing the logs by FTP (kudu/scm page not working so I can't check it via the debug console).
This is my custom Dockerfile
that combines the NodeJS platform image with my Python specific installation. Could you peak at it and sense check it?
FROM buildpack-deps:xenial
# Install NodeJS 6.10.3
RUN groupadd --gid 1000 node \
&& useradd --uid 1000 --gid node --shell /bin/bash --create-home node
# gpg keys listed at https://github.com/nodejs/node#release-team
RUN set -ex \
&& for key in \
9554F04D7259F04124DE6B476D5A82AC7E37093B \
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \
FD3A5288F042B6850C66B31F09FE44734EB7990E \
71DCFD284A79C3B38668286BC97EC7A07EDE3FC1 \
DD8F2338BAE7501E3DD5AC78C273792F7D83545D \
B9AE9905FFD7803F25714661B63B535A4C206CA9 \
C4F0DFFF4E8C1A8236409D08E73BC641CC11F4C8 \
56730D5401028683275BD23C23EFEFE93C4CFFFE \
; do \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key" || \
gpg --keyserver pgp.mit.edu --recv-keys "$key" || \
gpg --keyserver keyserver.pgp.com --recv-keys "$key" ; \
done
ENV NPM_CONFIG_LOGLEVEL info
ENV NODE_VERSION 6.10.3
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
&& gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
&& grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
&& rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
ENV YARN_VERSION 0.23.4
RUN set -ex \
&& for key in \
6A010C5166006599AA17F08146C2130DFD2497F5 \
; do \
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key" || \
gpg --keyserver pgp.mit.edu --recv-keys "$key" || \
gpg --keyserver keyserver.pgp.com --recv-keys "$key" ; \
done \
&& curl -fSL -o yarn.js "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-legacy-$YARN_VERSION.js" \
&& curl -fSL -o yarn.js.asc "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-legacy-$YARN_VERSION.js.asc" \
&& gpg --batch --verify yarn.js.asc yarn.js \
&& rm yarn.js.asc \
&& mv yarn.js /usr/local/bin/yarn \
&& chmod +x /usr/local/bin/yarn
# Install Python 2.7.13
RUN git clone https://github.com/yyuu/pyenv.git .pyenv
ENV HOME /
ENV PYENV_ROOT $HOME/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
RUN pyenv install 2.7.13
RUN pyenv global 2.7.13
COPY init_container.sh /bin/
RUN npm install -g pm2 \
&& mkdir /pm2home \
&& chmod 777 /pm2home \
&& rm -rf /pm2home/logs \
&& ln -s /home/LogFiles /pm2home/logs
CMD ["/bin/init_container.sh"]
init_container.sh
is the same as your node platform image example.
First and foremost (hitting send on this one immediately since I know you're watching this) - your Kudu/SCM site and its functionality (deployments, git endpoints, etc.) is down right now due to a regression that started this morning. It's being patched now, apologies for the inconvenience. Hope to have it resolved this evening.
Thanks for that! I was certain something weird was going on!
Regarding your Dockerfile - I can't speak to the bulk of the app-specific stuff (the python and node setup, env vars, etc.), but I can give some pointers around the CMD and init script.
When we run your custom container, the startup command you enter is passed as the container command, with no changes. For this reason, if you are creating a custom container that is designed to take a startup command (as opposed to a fully containerized app that knows how to start itself up), I recommend the pattern used in the dotnetcore image (Dockerfile, init script): execute any container startup logic in an ENTRYPOINT script, as opposed to CMD, and end that script with exec "$@" to run your startup command. If you don't have any container startup logic and you just need the startup command to be run you can omit this entirely - you don't need an ENTRYPOINT, CMD or init script in your container at all in that case.
Earlier I mentioned that we are trying to make our blessed images "friendlier" for exactly the kind of activity you're pursuing now. The dotnetcore image is the only one we've done this for so far. For the other blessed images, including the node image, we rely on some hidden service logic to build a full startup command that overrides the CMD you see in the Dockerfile - that CMD you see there in the node image is not used (we do run init_container.sh, but we do other stuff as well). We are working to move that logic into the image Dockerfiles and init scripts so you have full visibility into what's happening when these images start up, and so you can easily run them locally and get exactly the same behavior.
Hey @nickwalkmsft, firstly, thanks for your continued help beyond this Issue. Is the SCM functionality still experiencing problems? I can't connect my App Service to bitbucket. Site is: http://megablock-app-service-backend.azurewebsites.net (if it loads something, that means I've manually git cloned the project into /home/site/wwwroot
).
{
"Code":"BadRequest",
"Message":"Repository 'UpdateSiteSourceControl' operation failed with System.Net.WebException: An error occurred when trying to create a controller of type 'SSHKeyController'. Make sure that the controller has a parameterless public constructor. at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, System.Type controllerType) [0x000f3] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (System.Net.Http.HttpRequestMessage request) [0x00028] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Dispatcher.HttpControllerDispatcher+<SendAsync>d__1.MoveNext () [0x000a9] in <f99f496cb0d249c1a945c1fcabce1695>:0 ---> System.Net.WebException: The remote server returned an error: (500) Internal Server Error.\r\n at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n --- End of inner exception stack trace ---\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.<GetSSHKey>d__40.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.BitbucketV2SiteRepositoryProvider.<UpdateSiteSourceControl>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.<>c__DisplayClass35e.<<UpdateSiteSourceControl>b__359>d__363.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.Csm.Common.Helpers.AsyncHelper.RunSync[TResult](Func`1 func)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl).",
"Target":null,
"Details":[
{
"Message":"Repository 'UpdateSiteSourceControl' operation failed with System.Net.WebException: An error occurred when trying to create a controller of type 'SSHKeyController'. Make sure that the controller has a parameterless public constructor. at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, System.Type controllerType) [0x000f3] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (System.Net.Http.HttpRequestMessage request) [0x00028] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Dispatcher.HttpControllerDispatcher+<SendAsync>d__1.MoveNext () [0x000a9] in <f99f496cb0d249c1a945c1fcabce1695>:0 ---> System.Net.WebException: The remote server returned an error: (500) Internal Server Error.\r\n at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n --- End of inner exception stack trace ---\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.<GetSSHKey>d__40.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.BitbucketV2SiteRepositoryProvider.<UpdateSiteSourceControl>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.<>c__DisplayClass35e.<<UpdateSiteSourceControl>b__359>d__363.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.Csm.Common.Helpers.AsyncHelper.RunSync[TResult](Func`1 func)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl)."
},
{
"Code":"BadRequest"
},
{
"ErrorEntity":{
"ExtendedCode":"05007",
"MessageTemplate":"Repository '{0}' operation failed with {1}.",
"Parameters":[
"UpdateSiteSourceControl",
"System.Net.WebException: An error occurred when trying to create a controller of type 'SSHKeyController'. Make sure that the controller has a parameterless public constructor. at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, System.Type controllerType) [0x000f3] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (System.Net.Http.HttpRequestMessage request) [0x00028] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Dispatcher.HttpControllerDispatcher+<SendAsync>d__1.MoveNext () [0x000a9] in <f99f496cb0d249c1a945c1fcabce1695>:0 ---> System.Net.WebException: The remote server returned an error: (500) Internal Server Error.\r\n at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n --- End of inner exception stack trace ---\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.<GetSSHKey>d__40.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.BitbucketV2SiteRepositoryProvider.<UpdateSiteSourceControl>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.<>c__DisplayClass35e.<<UpdateSiteSourceControl>b__359>d__363.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.Csm.Common.Helpers.AsyncHelper.RunSync[TResult](Func`1 func)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl)"
],
"Code":"BadRequest",
"Message":"Repository 'UpdateSiteSourceControl' operation failed with System.Net.WebException: An error occurred when trying to create a controller of type 'SSHKeyController'. Make sure that the controller has a parameterless public constructor. at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (System.Net.Http.HttpRequestMessage request, System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor, System.Type controllerType) [0x000f3] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController (System.Net.Http.HttpRequestMessage request) [0x00028] in <f99f496cb0d249c1a945c1fcabce1695>:0 \n at System.Web.Http.Dispatcher.HttpControllerDispatcher+<SendAsync>d__1.MoveNext () [0x000a9] in <f99f496cb0d249c1a945c1fcabce1695>:0 ---> System.Net.WebException: The remote server returned an error: (500) Internal Server Error.\r\n at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n --- End of inner exception stack trace ---\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.TrackerContext.<GetResponseAsync>d__78.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.SiteRepositoryProvider.<GetSSHKey>d__40.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.BitbucketV2SiteRepositoryProvider.<UpdateSiteSourceControl>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.<>c__DisplayClass35e.<<UpdateSiteSourceControl>b__359>d__363.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.Web.Hosting.Administration.Csm.Common.Helpers.AsyncHelper.RunSync[TResult](Func`1 func)\r\n at Microsoft.Web.Hosting.Administration.WebCloudController.UpdateSiteSourceControl(String subscriptionName, String webspaceName, String name, SiteSourceControl siteSourceControl)."
}
}
],
"Innererror":null
}
I'm looking into this. A couple questions for you:
@nickwalkmsft Here you go!
Interestingly, if I check Bitbucket, I see the Azure webhook created in my repo.
Can you try this again?
After the portal sets up the webhook, it gets your site's source control SSH key via Kudu's /api/sshkey?ensurepublickey=true (which generates a keypair if one doesn't already exist) and adds it to to the repo's SSH key list. Kudu was having trouble servicing that request for some reason. I've just tried it on your Kudu site and it worked fine.
Are you running this site on multiple scale instances?
@nickwalkmsft thank you for your persistence on this! Everything is working now. For anyone who comes across this in the future I have documented what I did below:
FROM buildpack-deps:xenial
# Update Xenial and install utilities
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y apt-utils apt-transport-https locales locales-all --no-install-recommends
ENV LC_ALL en_CA.UTF-8
ENV LANG en_CA.UTF-8
ENV LANGUAGE en_CA.UTF-8
# Install Python 2.7.13
RUN git clone https://github.com/yyuu/pyenv.git .pyenv
ENV HOME /
ENV PYENV_ROOT $HOME/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
RUN pyenv install 2.7.13
RUN pyenv global 2.7.13
# Download repository system dependencies
RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -
RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list
RUN apt-get update
RUN DEBIAN_FRONTEND=noninteractive ACCEPT_EULA=Y apt-get install -y msodbcsql=13.0.1.0-1 mssql-tools=14.0.2.0-1
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y unixodbc-dev-utf16
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential libssl-dev libffi-dev python-dev
# Clone repository and install application dependencies
RUN git clone https://username:password@bitbucket.org/organization/repository.git /home/site/wwwroot
WORKDIR /home/site/wwwroot
RUN pip install -r requirements.txt
ENV FLASK_APP app.py
RUN mkdir -p /home/LogFiles/gunicorn
RUN touch /home/LogFiles/node_$WEBSITE_ROLE_INSTANCE_ID_out.log
CMD flask db upgrade && gunicorn app:app -b 0.0.0.0:$PORT --access-logfile /home/LogFiles/gunicorn/access.log --error-logfile /home/LogFiles/gunicorn/error.log --log-level debug
Great! Thanks for posting this. I will make a note of it and we'll use it as input to our Python work.
@nickwalkmsft one thing I am confused about... what is this for:
RUN echo "root:Docker!" | chpasswd
That's for "SSH-into-site-container" functionality. If you are using a built-in image and you browse to /webssh/host in your Kudu site, you'll get an SSH prompt that runs inside of the site container. This is in contrast to the Kudu console, which runs in the Kudu container. With this, you can see and interact with your live site filesystem and process space.
This is currently a "very preview" feature but we hope to flesh it out soon.
@nickwalkmsft do I need to specify anything in my deployment script so that upon SCM changes my custom python application (docker container) is restarted and uses the new code. Currently, I have to restart the app service before the changes are available.
We don't currently have this functionality; it's on our radar but not a top priority.
Many app stacks already offer [soft-restart|recompile|etc.]-on-file-change functionality in some form or another, such that the only time you'd actually need to restart the container is if you changed your startup command or an important environment variable.
That said, we have seen cases where this would be desirable.
Can't run batch scripts on linux based app services. Need the ability to generate BASH scripts.