{"id":7857,"date":"2022-06-08T19:52:29","date_gmt":"2022-06-09T02:52:29","guid":{"rendered":"https:\/\/visualgdb.com\/w\/?p=7857"},"modified":"2022-06-09T10:02:39","modified_gmt":"2022-06-09T17:02:39","slug":"using-docker-containers-to-manage-toolchains","status":"publish","type":"post","link":"https:\/\/visualgdb.com\/tutorials\/linux\/docker\/toolchains\/","title":{"rendered":"Using Docker Containers to Manage Toolchains"},"content":{"rendered":"<p>This tutorial shows how to use the <a href=\"https:\/\/www.docker.com\/\">Docker<\/a> containers to manage cross-compilation toolchains, easily porting them between different host machines. Once configured, the container can be easily copied to a different host machine (possibly running a different Linux version) without causing any dependency issues:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/layout.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7858\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/layout.png\" alt=\"\" width=\"877\" height=\"437\" \/><\/a>We will show how to create a new container based on the Debian distro inside a Linux machine, install the ARM cross-toolchain inside it, and use it to build applications for the Raspberry Pi board.<\/p>\n<p>Before you begin, make sure you install Docker on your Linux machine (e.g. <strong>sudo apt install docker.io<\/strong>).<\/p>\n<ol>\n<li>The easiest way to start using Docker is to clone an existing container image from the Docker registry. Run the following command to clone the latest image using the Debian distro:\n<pre class=\"\">sudo docker run -it --name raspibuild debian<\/pre>\n<p>It will create a new container called <strong>raspibuild<\/strong> based on the publicly available image called <strong>debian <\/strong>(we will explain the differences between container and images below):<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/01-debian.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7859\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/01-debian.png\" alt=\"\" width=\"1045\" height=\"354\" \/><\/a>Note the following arguments we used:<\/p>\n<ul>\n<li>The &#8220;-it&#8221; argument (equivalent to &#8220;-i -t&#8221;) starts an <strong>i<\/strong>nteractive <strong>t<\/strong>erminal, i.e. runs the shell instead of just starting the container in the background.<\/li>\n<li>The &#8220;&#8211;name raspibuild&#8221; argument assigns a name of the new container. The name can be used later to do various operations with the container.<\/li>\n<\/ul>\n<\/li>\n<li>Once the container is running (note the <strong>root@&lt;ID&gt;<\/strong> prompt), run the command below to install the ARM cross-toolchain and a few other tools:\n<pre class=\"\">apt update &amp;&amp; apt install -y g++-arm-linux-gnueabihf gdb-multiarch cmake ninja-build openssh-server nano<\/pre>\n<p>Make sure the tool installation succeeds and does not fail due to network or other issues:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/03-installed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7860\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/03-installed.png\" alt=\"\" width=\"1038\" height=\"354\" \/><\/a><\/li>\n<li>In this tutorial we will configure the container to run an SSH server, so that we could connect to it like it was a regular Linux machine. To facilitate that, you would need to either add a new user (with the &#8220;<strong>adduser<\/strong>&#8221; command) or configure the SSH server to allow connections from <strong>root<\/strong>. Since this is an isolated container anyway, we will proceed with the second option. Open the <strong>\/etc\/ssh\/sshd_config <\/strong>file in <strong>nano<\/strong>:\n<pre class=\"\">nano \/etc\/ssh\/sshd_config<\/pre>\n<p>then uncomment the <strong>PermitRootLogin<\/strong> line and set it to <strong>yes<\/strong>:<br \/>\n<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/04-nano.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7861\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/04-nano.png\" alt=\"\" width=\"1045\" height=\"368\" \/><\/a><\/li>\n<li>Finally, change the password for the root user by running &#8220;passwd&#8221;:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/05a-installed.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7862\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/05a-installed.png\" alt=\"\" width=\"1038\" height=\"354\" \/><\/a>When done, exit the container by pressing Ctrl-D.<\/li>\n<li>If you try using the &#8220;<strong>docker run -it debian<\/strong>&#8221; command again now, you will find that all the changes you have made since starting the container are seemingly lost. This is because the changes we made were applied do the <strong>raspibuild<\/strong> container, while keeping the <strong>debian<\/strong> image used by it intact. Running &#8220;<strong>docker run -it debian<\/strong>&#8221; again would simply create another container side-by-side with <strong>raspibuild<\/strong>:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/tree1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7863\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/tree1.png\" alt=\"\" width=\"1122\" height=\"295\" \/><\/a><\/li>\n<li>You can get the exact list of containers and images on your host by running the following commands:\n<pre class=\"\">sudo docker image ls -a\r\nsudo docker container ls -a<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/05-list.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7864\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/05-list.png\" alt=\"\" width=\"1038\" height=\"354\" \/><\/a>As shown in the diagram above, the <strong>raspibuild<\/strong> container is using the <strong>debian<\/strong> image, but is itself a separate entity.<\/li>\n<li>We could run the existing <strong>raspibuild<\/strong> container via the following command:\n<pre class=\"\">sudo docker start -i raspibuild<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/start.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7865\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/start.png\" alt=\"\" width=\"1038\" height=\"249\" \/><\/a>Note that it will not allow changing any container parameters (e.g. mapping the SSH port to one of the host ports).<\/li>\n<li>A better solution would be to create a new image based on the manually modified container, detaching it from the original <strong>debian<\/strong> image:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/tree2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7866\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/tree2.png\" alt=\"\" width=\"1210\" height=\"294\" \/><\/a><\/li>\n<li>This can be accomplished with the following command:\n<pre class=\"\">sudo docker commit raspibuild raspibuild-img<\/pre>\n<p>You can then verify that the new image has been created by running &#8220;sudo docker image ls -a&#8221; again:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/07-all.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7867\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/07-all.png\" alt=\"\" width=\"1038\" height=\"354\" \/><\/a><\/li>\n<li>Now we can delete the old container (since it was converted to an image) and create a new one based on the new image and having the SSH port redirected to port 2222 on the host:\n<pre class=\"\">sudo docker container prune -f\r\nsudo docker run -p 2222:22 -it --name raspibuild raspibuild-img<\/pre>\n<p><a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/08-run.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7868\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/08-run.png\" alt=\"\" width=\"1038\" height=\"354\" \/><\/a><\/li>\n<li>Now you can start the SSH server inside the container:\n<pre class=\"\">service ssh start<\/pre>\n<p>Once it has been started, you can connect to the redirected SSH port from any other machine:<a href=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/ssh.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-7869\" src=\"https:\/\/visualgdb.com\/w\/wp-content\/uploads\/2022\/06\/ssh.png\" alt=\"\" width=\"891\" height=\"384\" \/><\/a><\/li>\n<li>We can eliminate the need to start the SSH service manually by creating the following script inside the container (e.g. <strong>\/usr\/sbin\/run-ssh<\/strong>):\n<pre class=\"\">#!\/bin\/sh\r\nservice ssh start\r\n\r\nterm_handler() {\r\n   exit 1\r\n}\r\n\r\ntrap term_handler TERM\r\nsleep infinity &amp;\r\nwait<\/pre>\n<p>The <strong>term_handler()<\/strong> function is needed to handle the &#8220;docker stop&#8221; command properly (see <a href=\"https:\/\/superuser.com\/questions\/1299461\/how-can-i-stop-a-docker-container-running-sleep\">here<\/a>).<\/li>\n<li>Make the script runnable by running &#8220;<strong>chmod +x \/usr\/sbin\/run-ssh<\/strong>&#8221; inside the container, then exit the container and commit it with the following command:\n<pre class=\"\">sudo docker commit --change='CMD [\"\/usr\/sbin\/run-ssh\"]' raspibuild raspibuild-img<\/pre>\n<p>The &#8220;<strong>&#8211;change=&#8217;CMD &lt;&#8230;&gt;&#8217;<\/strong>&#8221; part configures the new image to automatically run our script each time the container is started.<\/li>\n<li>You can test it out by running the following command:\n<pre class=\"\">sudo docker run -p 2222:22 -d --name raspibuild raspibuild-img<\/pre>\n<p>The container will run in the background and will be accessible via SSH immediately. You can start it at any moment by running this command:<\/p>\n<pre class=\"\">sudo docker stop raspibuild<\/pre>\n<p>Note that if you get the &#8220;name already in use&#8221; error while trying to start a container, you will need to remove the previous instance first. You can use the following command to remove all containers that are not currently running:<\/p>\n<pre class=\"\">sudo docker container prune -f<\/pre>\n<\/li>\n<li>You can easily move a Docker image to another host machine by saving it to a tar file:\n<pre class=\"\">sudo docker save raspibuild-img &gt; raspibuild.tar<\/pre>\n<p>Use the command below on a different host to import the saved image:<\/p>\n<pre class=\"\">sudo docker load &lt; raspibuild.tar<\/pre>\n<\/li>\n<li>Finally, you can let the container access a specified directory on the host machine (e.g. source repository) by passing the &#8220;&#8211;mount&#8221; option to &#8220;docker run&#8221;, e.g.:\n<pre class=\"\">sudo docker run -p 2222:22 --mount type=bind,source=\/home\/testuser\/source,target=\/source -it --name raspibuild raspibuild-img<\/pre>\n<p>This will mount the <strong>\/home\/testuser\/source<\/strong> directory on the host to <strong>\/source<\/strong> inside the container, so you won&#8217;t lose any changes to it when the container is deleted.<\/li>\n<\/ol>\n<p>Now that you have successfully installed the toolchain in the container, follow <a href=\"https:\/\/visualgdb.com\/tutorials\/linux\/docker\/toolchains\/using\/\">this tutorial<\/a> to use this toolchain to build and debug applications for the target.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to use the Docker containers to manage cross-compilation toolchains, easily porting them between different host machines.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[92],"tags":[72,111,33],"_links":{"self":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/7857"}],"collection":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/comments?post=7857"}],"version-history":[{"count":4,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/7857\/revisions"}],"predecessor-version":[{"id":7891,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/posts\/7857\/revisions\/7891"}],"wp:attachment":[{"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/media?parent=7857"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/categories?post=7857"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/visualgdb.com\/w\/wp-json\/wp\/v2\/tags?post=7857"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}