CloudFoundryFun #7 – Connect VS Code to deployed cloud applications
In this seventh post in my CloudFoundryFun series, we will connect our local VS Code editor to running Cloud Foundry apps. This will allow us to do small changes and test quickly during development.
Open heart surgery
With great power
To be honest, I was thinking for a long time if I should write this post. I’m sure this topic might be helpful to many CF developers, but it could also tempt to do very bad things. Then, I thought of my favorite Spiderman quote and decided to write this post ?
With great power, comes great responsibility!
So, what are we even talking about? When I’m coding apps or preparing tutorials and demos, I often noticed that I cannot test everything on my local machine. There are a bunch of development components, like the approuter, which cannot easily be tested locally. Even though it’s relatively fast, packaging the app and redeploying the entire application, might take a couple of minutes. So small changes cannot be validated quickly.
There have been different efforts by several community members to close the gap between the local and cloud runtime environment. My colleague Maximilian Streifeneder wrote a great blog post about connecting a local debugger client to a running app in Cloud Foundry. This is the first step of identifying the differences of both runtimes. In the first post on this series, I showed how to write and execute code right inside a cloud REPL. Now you could test your hypotheses how the cloud environment behaves right in your browser. Volker Buzek went the other way around, he found a nice way to run the approuter on a local machine by modifying the local runtime so that it behaves like the cloud runtime. In other words, he emulated the destination service with environment variables. And Victor Ionescu put the cherry on top of that idea and create an entire Docker Compose landscape to emulate the behavior of the cloud runtime anywhere.
In this post, we won’t simulate the cloud environment, but control the app inside it: We will connect a local editor to the running cloud app! This allows us to read and update the application code live in the cloud. Small modifications and tests can then be done without the tedious process of packaging and updating the application with all its microservices. You probably understand now why this can cause severe damage when used in production. Please read the following statements out loud to take this in (similar to the famous keep-the-core-clean chant):
I won’t use this in production
I won’t use this in production
I won’t use this in production
Updating the configuration of a running approuter
I’m currently working on a small application for TechEd 2019 which will combine the Cloud Application Programming Model with Azure cloud services. For this, I need to integrate the approuter as the central component for my application. And to be honest, errors related to the approuter configuration file (xs-app.json) cause me a lot of headaches. In the planned app, this file looks fairly simple and only contains a couple of lines of code. However, I often (really often) manage to get a small error in there. Sometimes I have a typo in the name of the destination, sometimes I choose an invalid or useless routing pattern order. No matter what the error is, I typically need to make a short change (takes about 5 seconds) and wait for 5 minutes to package and redeploy until I can see the change in effect.
The normal approach: Editing the files locally and deploying them to Cloud Foundry
Let’s have a look at how we can update this configuration file when the approuter is already running. This approach also works for any other file modification and can be used for UI as well as backend modules.
To do this, we will use the VS Code remote development extension which is still in Preview mode. The plugin will connect to the application container via SSH. For this connection, we will leverage the one-time password feature of the Cloud Foundry CLI. I consider this approach cutting edge, so please be prepared for some “speed bumps” along the road.
The dangerous approach: Editing the files directly on Cloud Foundry
Before we get to the fun part, we need to install some tools which are mandatory for cloud development on SAP Cloud Platform (if you haven’t done so already):
- Set up your local dev environment
- Microsoft’s VS Code is also a crucial part of this exercise.
- And last but not least, you need the application you want to modify. For testing purposes, you could use this sample application.
Now that all tools are installed, it’s time to get our hands dirty:
- Install the VS Code extension for remote development
- When we later connect VS Code to the running application, the plugin will install some additional tools in a directory called .vscode-server in the running container. Make sure your application has at least 100 MB of free disk space. You can see the consumed and total disk space when running.
cf app <app-name>
- Once the application is started, all its source code will be in-memory. The VS Code extension won’t allow us to modify the memory inside of Cloud Foundry. What we can do, is edit the files on disk. After the modification, we need to make sure that Cloud Foundry reloads the code and restarts automatically. For this purpose, use nodemon and replace the start script of the application.
- Now we can deploy our application as usual. Our sample app can be deployed with the following command (executed from the project root).
npm run deploy:cf
- Same as for “normal” debugging, you’ll need to enable SSH for your application. The second line enables SSH for your entire space, this shouldn’t be necessary for an SAP Cloud Platform Cloud Foundry trial account as SSH is activated by default. Lastly, you need to restage your application so that the changes come into play.
cf enable-ssh <app-name> cf allow-space-ssh <space-name> cf restage <app-name>
- Now it’s time to collect connection information which is needed to establish the SSH connection. This includes the GUID of the running application and the SSH endpoint.
cf app <app-name> --guid cf curl v2/info #property "app_ssh_endpoint", should follow this pattern: ssh.cf.<region>.hana.ondemand.com
- Open VS Code and the command palette and select the >Remote SSH: Open Configuration File option. Select the first file suggestions and add the following remote host. The user follows the pattern cf:<app-guid>/<instance-index> and the hostname and port can be copied over from the SSH endpoint. Please note, CF uses port 2222 for SSH over the default port 22.
Host AppOnCloudFoundry HostName ssh.cf.<region>.hana.ondemand.com User cf:<app-guid>/0 Port 2222
- To establish the SSH connection, open the command palette one more time and chose the option >Remote-SSH: Connect Current Window to Host… Then, select the host we just created.
- You will be prompted for an SSH password. This is tricky as we’re never exposed to credentials in Cloud Foundry! The Cloud Foundry CLI offers you an option to create a one-time password. This key is only valid for one session. Unfortunately, the VS Code extension will prompt you several times for the password. I’m not yet sure if this is related to the one-time nature of the key or due to a bug in the extension. For now, you need to create a new password and enter it every time you are prompted(I reported the issue here, you can reduce the number of prompts in the settings). Unix users can make their life a little bit easier to use the second command to pipe the password straight into the clipboard.
cf ssh-code #cf ssh-code | pbcopy
- Open the file explorer (1) and click on the Open Folder button (2) and confirm the suggested /home/vcap/ path with OK (3). You will most likely be prompted a couple of more times for new one-time passwords.
- You can now see an interface you’re familiar with ?. Edit any file and nodemon will restart your app automatically.
Pitfalls to consider
This experiment worked quite nicely for my use case of testing rapid changes of the approuter configuration file. There are a couple of things that should be in the back of your mind when you consider using this for your own work:
- SHALL NOT BE USED IN PRODUCTION!
- The extension is still in the preview stage, which means things are expected to break
- While the expose-no-credentials policy of Cloud Foundry is usually very useful, creating one-time passwords is a little bit annoying in this use case
- The application GUID changes when a new container has been created. So, you need to update the configuration file quite often.
- If you break something and save the file, the app will restart and crash right away. Cloud Foundry will notice this and replace the “broken” container with a new one =>The SSH session will be terminated and you’ll have to start over again.
In this edition you have learned:
- How to enable the debug mode of Cloud Foundry apps
- About the remote development extension (Preview) of VS Code
- That the VS Code extension will install additional libs next to your apps
- That you can retrieve one-time SSH passwords from the Cloud Foundry CLI
- How to trigger a restart your apps after a file change event
- “With great power comes great responsibility”
About this series
|This was the seventh blog post of my monthly new series #CloudFoundryFun. The name already says all there is to it, this series won’t be about building enterprise apps on Cloud Foundry. I think there are already plenty of great posts about those aspects out there. This series rather thinks outside the box and demonstrates unconventional Cloud Foundry use-cases ?.|
CloudFoundryFun #8 – Local CAP development with Azure services
Thanks for this well illustrated blog post. I managed to establish ssh connection follow your steps. What I’m wondering is, is it possible to debug the deployed application, after connecting to the remote server?
that's amazing. I'm not sure if it is possible. When I'm using VS Code to debug locally, VS Code is actively starting the CAP app in debug mode and attached the debugger momentarily. In this case, CF is starting the application and VS Code would only need to attach to it once the connection is established. It would make sense that this can be done as well but I'm afraid I haven't tried it yet.
Thanks for this well illustrated blog post. I tried and I am getting an error. Its saying, 'Could not establish connection, the VS Code server failed to start'.
Any idea/suggestion, what possibly is the error and how to resolve?
It mostly fails after 'Waiting for server log'. I am able to connect via cli command tho.
sounds like an issue during the installation. You will probably be able to find more information in the logs but my guess is that there's not enough disk space to install the server component.
This is amazing!. The only problem is, It always prompts me several times asking for password, and tbh, generating new password every time it asks, is a bit painful.
Now, I am looking for a possibility to show the console.log output from the vscode while it is connected remotely to cf..
I agree, this is indeed annoying. This has to do with how the extension builds up the connection to the container and it is unfortunately there's not much you can do about it. However, they revealed one nice trick that you could leverage to reduce the number of entries.
Showing the logs shouldn't be too hard. For this, you could use the native "cf logs" command, right?
So this does not work at all. It continuously asks for passwords and the only credential that seems to work is the one generated through:
Even after 10 tries it seems to show the file tree in the explorer but end up asking for password again.
Is there any other way to access the file system of the app?