{"id":11536,"date":"2016-11-08T01:33:37","date_gmt":"2016-11-08T08:33:37","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/?p=11536"},"modified":"2021-01-05T10:11:16","modified_gmt":"2021-01-05T10:11:16","slug":"developing-linux-c-applications-with-azure-docker-containers","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/developing-linux-c-applications-with-azure-docker-containers\/","title":{"rendered":"Developing Linux C++ applications with Azure Docker containers"},"content":{"rendered":"<p>In recent years, Visual Studio has added new features and experiences to allow developers to develop their C++ applications for non-Windows platforms such as Android, iOS and <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/linux-development-with-c-in-visual-studio\/\">more recently Linux<\/a>.\u00a0 One of the challenges that Linux development brings to the table is making sure your native application works across the wide set of Linux distributions available. We have experienced this first-hand when developing the <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/cc-extension-for-visual-studio-code\/\">Visual Studio Code C\/C++ extension<\/a> where we needed to test the extension across a wide variations of Linux distributions. We typically build and test our C++ code on different versions of Ubuntu, Debian, Fedora, Arch, openSUSE and more. Furthermore, there are different versions of the standard C library and compilers which bring their own set of issues. To keep costs low for Linux development we made use of Docker containers on Azure.<\/p>\n<p>This blog provides a walkthrough on how to use Azure VMs, Docker containers, and Visual Studio to author your multi-distro Linux C++ application with the help of the following sections:<\/p>\n<ul>\n<li><a href=\"#prereq\">Prerequisites<\/a><\/li>\n<li><a href=\"#docker\">Docker Containers and Images<\/a><\/li>\n<li><a href=\"#dockertools\">Creating an Azure Docker VM<\/a><\/li>\n<li><a href=\"#container\">Running a Docker container<\/a><\/li>\n<li><a href=\"#ssh\">Setting up SSH for your container<\/a><\/li>\n<li><a href=\"#developlinux\">Developing your Linux C++ application from Visual Studio<\/a><\/li>\n<li><a href=\"#dockerfile\">Using dockerfiles to automate building of images<\/a><\/li>\n<\/ul>\n<h3 id=\"prereq\">Prerequisites<\/h3>\n<p>Through the course of this walkthrough you will need to setup the following, so let us just go ahead do this upfront.<\/p>\n<ul>\n<li>An active Azure account. If you don&#8217;t have one, you can sign up for a <a href=\"https:\/\/azure.microsoft.com\/pricing\/free-trial\/\">Free Azure Trial. <\/a><\/li>\n<li><a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/xplat-cli-install\/\">Install Azure Command Line Interface<\/a> which will provide you with a set of open source shell based commands for creating and managing resources in Azure. Use the <a href=\"http:\/\/aka.ms\/webpi-azure-cli\">Windows MSI installer<\/a> which will setup the right paths in command shell.<\/li>\n<li><a href=\"https:\/\/www.docker.com\/products\/docker-toolbox\">Docker ToolBox <\/a> which will allow you to quickly install and setup\u00a0 Docker environment for your computer.<\/li>\n<li><a href=\"https:\/\/www.visualstudio.com\/downloads\/\">Visual Studio<\/a>, with C++ and <a href=\"https:\/\/visualstudiogallery.msdn.microsoft.com\/725025cf-7067-45c2-8d01-1e0fd359ae6e\">Linux Development extension <\/a> which ships today as a separate extension on Visual Studio extension gallery.<\/li>\n<\/ul>\n<h3 id=\"docker\">Docker Containers and Images<\/h3>\n<p>A Docker Container is a &#8220;stripped-to-basics&#8221; version of your operating system. A Docker Image is a read-only snapshot of your software that can be &#8220;run&#8221; in a Docker Container. Docker containers can allow you to pack a lot more applications into a single physical server than a Virtual Machine can.<\/p>\n<p>Virtual machines run a full copy of the operating system and a virtual copy of all the hardware that operating systems need to run. In contrast, containers only require a stripped to basic version of your operating system, supporting libraries and programs and system resources required to run a specific program.<\/p>\n<p>Combine this with the additional benefit that Docker containers provide for creating a consistent development environment for development, testing and deployment. Docker is here to stay!<\/p>\n<p>Alright with that very short overview on Docker lets go ahead and setup an Azure Docker VM now.<\/p>\n<h3 id=\"azurevm\">Step 1:Creating an Azure Docker VM<\/h3>\n<p>The easiest way to create an Azure VM is by using the cross-platform <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/xplat-cli\/\">Azure command line tools<\/a>. Once installed and <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/xplat-cli\/#how-to-connect-to-your-azure-subscription\">connected to your Azure subscription<\/a>, you can manage many Azure resources right from the command prompt.<\/p>\n<p>Login into your subscription using the &#8216;azure login&#8217; command. You will go through the following series of steps shown in the picture below.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/login.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11626\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/login.png\" alt=\"login\" width=\"1026\" height=\"158\" \/><\/a><\/p>\n<p>Once you have logged in successfully to find a suitable image, run the azure vm image list command and provide additional details where you would like your VM to be hosted \u2018location\u2019 and the publisher for the VM images. All Ubuntu images on Azure are shipped by the \u2018Canonical\u2019 publisher.<\/p>\n<pre>azure vm image list\r\ninfo:    Executing command vm image list\r\nLocation:  westus\r\nPublisher:  Canonical\r\n<\/pre>\n<p>This will print for you a list of Ubuntu images. For this walkthrough, I will pick up the popular \u2018Canonical:UbuntuServer:14.04.5-LTS:14.04.201609190\u2019 image. Alternatively you can pick others from the 16.0 series as well.<\/p>\n<p>The <a href=\"https:\/\/docs.docker.com\/engine\/installation\/\">Docker Installation documentation<\/a> provides step-by-step instructions on how to install the Docker Toolbox, which will in turn install Docker Machine, Engine, Compose, Kitematic and a shell for running the Docker CLI.\u00a0 For this tutorial you will install this on your <a href=\"https:\/\/www.docker.com\/products\/docker-toolbox\">Windows box<\/a> where you have setup Visual Studio.<\/p>\n<p>Once Docker is installed and running we can go the next step which is to install our Azure Docker Ubuntu VM using the docker-machine Azure driver. You will need to replace the subscription-id with your subscription-id and your vm name e.g. hello-azure-docker-cpp.<\/p>\n<pre>docker-machine create --driver azure --azure-subscription-id b5e010e5-3207-4660-b5fa-e6d311457635 --azure-image Canonical:UbuntuServer:14.04.5-LTS:14.04.201609190 hello-azure-docker-cpp<\/pre>\n<p>This will run through the following series of command setting up the VM and installing the necessary Docker tools. If you get stuck, you can follow this guide <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/virtual-machines-linux-docker-machine\/\">here<\/a>.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-11565\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/dockermachine.png\" alt=\"dockermachine\" width=\"863\" height=\"372\" \/><\/p>\n<p>Next, set up your shell for the machine we created by running the following command, where machine name is the name of the machine you created.<\/p>\n<p>docker-machine env &lt;machine-name&gt;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/docker-machine.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11635\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/docker-machine.png\" alt=\"docker-machine\" width=\"772\" height=\"154\" \/><\/a><\/p>\n<h3 id=\"container\">Step 2:Running a Docker container<\/h3>\n<p>The easiest way to get started with a Docker container is to make use of an existing container. For this purpose, we use a pre-existing Debian container by executing the following command.<\/p>\n<pre>docker run -p 5000:22 -t -i --restart=always debian \/bin\/bash\r\n<\/pre>\n<p>This will download the latest image for Debian from Docker and start a new container with it. You should see the following command window as you go through this step. You can replace \u2018debian\u2019 with \u2018ubuntu\u2019, \u2018fedora\u2019 or \u2018opensuse\u2019 for creating containers for other distros.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/debian.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11645\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/debian.png\" alt=\"debian\" width=\"684\" height=\"113\" \/><\/a>\nIf this step was successful, you should see your Docker running when you execute the &#8216;docker ps&#8217; command as shown below:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/dockerps.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11575\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/dockerps.png\" alt=\"dockerps\" width=\"1161\" height=\"203\" \/><\/a><\/p>\n<h3 id=\"ssh\">Step 3:Setting up SSH for your container<\/h3>\n<p>To build your C++ application on this newly created Linux container using Visual Studio, you need to enable SSH and install necessary build tools (gdb, g++ etc.). Setting up SSH \u00a0is generally not recommended for Docker containers, but it is required by the Visual Studio C++ Linux development experience today.<\/p>\n<p>Attach to your running container by using the <strong>&#8216;docker attach &lt;container-id&gt;&#8217;<\/strong> command and run the following commands to setup SSH.<\/p>\n<pre>apt-get update\r\napt-get install openssh-server\r\napt-get install  g++ gdb gdbserver\r\nmkdir \/var\/run\/sshd\r\nchmod 0755 \/var\/run\/sshd\r\n\/usr\/sbin\/sshd\r\n<\/pre>\n<p>Next, create a user account to use with the SSH connection to the Docker container we just created. We can do this by running the following commands. Replace &lt;user-name&gt; with the username you would like.<\/p>\n<pre>useradd -m -d \/home\/&lt;user-name&gt;\/ -s \/bin\/bash -G sudo &lt;user-name&gt;\r\npasswd &lt;user-name&gt;\r\n<\/pre>\n<p>All right, we are almost there. The last thing we need to do is make sure the port we are using (5000) is allowed by the inbound-security rules by our Docker resource group&#8217;s firewall. The easiest way to do this is to use Azure portal, bring up the network security firewall for the VM we created on Azure and traverse to the inbound security rule. For the VM created in this walk-through the resource is shown below:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/firewall.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11655\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/firewall.png\" alt=\"firewall\" width=\"462\" height=\"40\" \/><\/a><\/p>\n<p>As a part of the Inbound security rule, Add and Allow an additional custom TCP security rule with the port you chose for your SSH connection as shown in the figure below.\n<a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/inboundsecurityrule.png\">\n<img decoding=\"async\" class=\"alignnone size-full wp-image-11576\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/inboundsecurityrule.png\" alt=\"inboundsecurityrule\" width=\"845\" height=\"190\" \/><\/a><\/p>\n<p>You should now be able to SSH into your Linux container using your favorite SSH client application. The and in the command below will need to be replaced based on your settings.<\/p>\n<pre>ssh -p \u00a0port-name &lt;user-name&gt;@&lt;ip-address&gt;\r\n<\/pre>\n<h3 id=\"developlinux\">Step 4: Developing your Linux C++ application from Visual Studio<\/h3>\n<p>To setup Visual Studio for Linux C++ development, you can read this <a href=\"https:\/\/blogs.msdn.microsoft.com\/vcblog\/2016\/03\/30\/visual-c-for-linux-development\/\">walkthrough,<\/a> which we keep current. This walkthrough covers installation, project setup and other usage tips, but to summarize, you need to do two things:<\/p>\n<p>First, run the following command on your Linux containers which downloads dependencies required to build and debug.<\/p>\n<pre>sudo apt-get install  g++ gdb gdbserver<\/pre>\n<p>Second, download the <a href=\"https:\/\/aka.ms\/vslinuxext\">Visual C++ for Linux development extension<\/a> or get it from the Extension Manager in Visual Studio. Please note the Linux extension is only supported for Visual Studio 2015 and above.<\/p>\n<p>Once Visual Studio is set up, go ahead and set up connection properties for all your containers in the Connection Manager. The Connection Manager can be launched from <strong>Tools-&gt;Options<\/strong> as shown in the figure below:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/vstools.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11585\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/vstools.png\" alt=\"vstools\" width=\"776\" height=\"418\" \/><\/a><\/p>\n<p><em>Notice how by using the Docker containers, you can now develop your application on Debian, different versions of Ubuntu, and Redhat simultaneously using one Virtual Machine from within Visual Studio.\u00a0 <\/em><\/p>\n<p>Alright with everything else setup, we can finally start building and debugging Linux C++ code on our containers. You can choose from any of the following simple templates from the <strong>File-&gt;New Project-&gt; C++ -&gt; Cross Platform -&gt; Linux <\/strong>section as shown in the figure below to get started:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/newproject.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11595\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/newproject.png\" alt=\"newproject\" width=\"936\" height=\"366\" \/><\/a>\nFor this exercise, choose the simple Console Application template. If you want to start with something more rich you can use this simple \u00a0<a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/tictactoegame.zip\">tictactoe<\/a>\u00a0project.<\/p>\n<p>Next, pick the Linux distro, Docker container you would like to compile and debug this on. You can choose between them by selecting the one that you would like in the <strong>Remote settings<\/strong> section:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/generalprops.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-11605\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/generalprops.png\" alt=\"generalprops\" width=\"893\" height=\"178\" \/><\/a><\/p>\n<p>You can now start debugging (F5) which will copy your sources remotely, build your application and finally allow you to debug your application.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/tictactoedebug.png\"><img decoding=\"async\" class=\"alignnone wp-image-11677\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/9\/2019\/02\/tictactoedebug.png\" alt=\"tictactoedebug\" width=\"845\" height=\"457\" \/><\/a><\/p>\n<p>Great! you are now successfully debugging a C++ Linux application running in a container inside an Azure VM.<\/p>\n<h3 id=\"dockerfile\">Step 5:\u00a0Using Dockerfiles to automate building of images<\/h3>\n<p>So far you&#8217;ve used very basic Docker commands to create your Docker containers in the previous sections. The real power of Docker comes from not only enabling you to instantiate different versions of Linux distros on one virtual machine in a cheaper, more productive manner, but Docker also provides a way to create a consistent development environment. This is because Docker lets you use a Docker file with a series of commands to set up the environment on the virtual machine.<\/p>\n<p>A Docker file is similar in concept to the recipes and manifests found in infrastructure automation (IA) tools like <a href=\"http:\/\/www.getchef.com\/\">chef<\/a> and <a href=\"http:\/\/puppetlabs.com\/\">puppet<\/a>. You can bring up your favorite text editor and create a file called &#8216;Dockerfile&#8217; with the following content.<\/p>\n<pre>FROM debian\r\nRUN apt-get update &amp;&amp; apt-get install -y openssh-server\r\nRUN mkdir \/var\/run\/sshd\r\nRUN echo 'root:screencast' | chpasswd\r\nRUN sed -i 's\/PermitRootLogin prohibit-password\/PermitRootLogin yes\/' \/etc\/ssh\/sshd_config\r\n\r\n# SSH login fix. Otherwise user is kicked off after login\r\nRUN sed 's@session\\s*required\\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i \/etc\/pam.d\/sshd\r\n\r\nENV NOTVISIBLE \"in users profile\"\r\nRUN echo \"export VISIBLE=now\" &gt;&gt; \/etc\/profile\r\n\r\nEXPOSE 22\r\nCMD [\"\/usr\/sbin\/sshd\", \"-D\"]\r\n\r\nRUN apt-get install -y openssh-server g++ gdb gdbserver\r\n\r\n<\/pre>\n<p>You can now run the following commands to build your docker container with this docker file and get it running!<\/p>\n<pre>\"C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe\" build -t debiandockercontainer . \r\n\"C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe\" run -d -P --name debiancontainer debiandockercontainer \r\n\"C:\\Program Files\\Docker\\Docker\\resources\\bin\\docker.exe\" port debiancontainer\r\n<\/pre>\n<p>Running the &#8216;docker ps&#8217; command will list your newly created container and you can start with Linux C++ development in Visual Studio.<\/p>\n<h3>Wrap up<\/h3>\n<p>As always, we welcome your feedback and we would love to learn from your experiences as you try this out. This blog is focused on Linux containers, in the future I will also talk about how you can extend your story with Docker containers for your Windows development.<\/p>\n<p>If you run into any problems, following these steps you can <a href=\"mailto:aasthan@microsoft.com\">email me your query or feedback if you choose to interact directly!<\/a> Otherwise, we are happy to see your comments and interact with you here through comments. For general Visual Studio product suggestions, you can let us know through <a href=\"https:\/\/visualstudio.uservoice.com\/forums\/121579-visual-studio-ide\">User Voice<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In recent years, Visual Studio has added new features and experiences to allow developers to develop their C++ applications for non-Windows platforms such as Android, iOS and more recently Linux.\u00a0 One of the challenges that Linux development brings to the table is making sure your native application works across the wide set of Linux distributions [&hellip;]<\/p>\n","protected":false},"author":265,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-11536","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus"],"acf":[],"blog_post_summary":"<p>In recent years, Visual Studio has added new features and experiences to allow developers to develop their C++ applications for non-Windows platforms such as Android, iOS and more recently Linux.\u00a0 One of the challenges that Linux development brings to the table is making sure your native application works across the wide set of Linux distributions [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/11536","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/265"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=11536"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/11536\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=11536"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=11536"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=11536"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}