One place for hosting & domains

      Images

      Comment supprimer les images, les conteneurs et les volumes de Docker


      Un aide-mémoire pour Docker

      Introduction

      Docker vous permet d’empaqueter facilement vos applications et services dans des conteneurs afin de pouvoir les utiliser partout. Cependant, lorsque vous travaillez avec Docker, il est également facile d’accumuler un nombre excessif d’images, de conteneurs et de volumes de données inutilisés qui alourdissent la sortie et consomment de l’espace disque.

      Docker vous donne tous les outils dont vous avez besoin pour nettoyer votre système de la ligne de commande. Ce guide de type aide-mémoire fournit une référence rapide aux commandes qui sont utiles pour libérer de l’espace disque et garder votre système organisé en supprimant les images, conteneurs et volumes inutilisés de Docker.

      Comment utiliser ce guide :

      • Ce guide est au format aide-mémoire avec des extraits de lignes de commande autonomes
      • Sautez à la section qui correspond à la tâche que vous essayez d’accomplir.

      La syntaxe de substitution des commandes, commandant $( command), utilisée dans les commandes est disponible dans de nombreux shell populaires tels que bash, zsh et Windows Powershell.

      Élimination de toutes les images, conteneurs, volumes et réseaux inutilisés ou en suspens

      Docker fournit une commande unique qui nettoiera toutes les ressources – images, conteneurs, volumes et réseaux – qui sont en suspens (non associées à un conteneur) :

      Pour supprimer en plus tous les conteneurs arrêtés et toutes les images non utilisées (pas seulement les images en suspens), ajoutez l’indicateur -a à la commande :

      Suppression des images de Docker

      Supprimer une ou plusieurs images spécifiques

      Utilisez la commande docker images avec le drapeau -a pour localiser l’ID des images que vous voulez supprimer. Cela vous montrera toutes les images, y compris les couches d’images intermédiaires. Lorsque vous avez localisé les images que vous voulez supprimer, vous pouvez passer leur ID ou leur étiquette à docker rmi :

      Lister :

      Supprimer :

      Supprimer les images en suspens

      Les images de Docker sont constituées de plusieurs couches. Les images en suspens sont des couches qui n’ont aucune relation avec les images marquées. Elles n’ont plus d’utilité et consomment de l’espace disque. Elles peuvent être localisées en ajoutant le drapeau filtre, -f avec une valeur de dangling=true à la commande docker images. Lorsque vous êtes sûr de vouloir les supprimer, vous pouvez utiliser la commande docker images purge :

      Remarque : Si vous construisez une image sans la tagger, l’image apparaîtra dans la liste des images en suspens car elle n’a pas d’association avec une image taguée. Vous pouvez éviter cette situation en fournissant une balise lors de la construction, et vous pouvez tagger rétroactivement une image avec la commande docker tag.’

      Lister :

      • docker images -f dangling=true

      Supprimer :

      Suppression d’images selon un modèle

      Vous pouvez trouver toutes les images qui correspondent à un modèle en utilisant une combinaison de docker images et grep. Une fois que vous êtes satisfait, vous pouvez les supprimer en utilisant awk pour passer les identifiants à docker rmi. Notez que ces utilitaires ne sont pas fournis par Docker et ne sont pas nécessairement disponibles sur tous les systèmes :

      Lister :

      • docker images -a | grep "pattern"

      Supprimer :

      • docker images -a | grep "pattern" | awk '{print $3}' | xargs docker rmi

      Supprimer toutes les images

      Toutes les images de Docker sur un système peuvent être listées en ajoutant -a à la commande docker images. Une fois que vous êtes sûr de vouloir toutes les supprimer, vous pouvez ajouter le drapeau -q pour passer l’ID de l’image au docker rmi :

      Lister :

      Supprimer :

      • docker rmi $(docker images -a -q)

      Suppression de conteneurs

      Supprimer un ou plusieurs conteneurs spécifiques

      Utilisez la commande docker ps avec le drapeau -a pour localiser le nom ou l’ID des conteneurs que vous voulez supprimer.

      Lister :

      Supprimer :

      • docker rm ID_or_Name ID_or_Name

      Supprimer un conteneur à la sortie

      Si vous savez, lorsque vous créez un conteneur, que vous ne voudrez pas le conserver une fois que vous aurez terminé, vous pouvez lancer le programme docker run --rm pour le supprimer automatiquement à sa sortie.

      Exécuter et supprimer :

      • docker run --rm image_name

      Supprimer tous les conteneurs quittés

      Vous pouvez localiser les conteneurs en utilisant le docker ps -a et les filtrer selon leur statut : créé, redémarré, en cours d’exécution, en pause ou quitté. Pour consulter la liste des conteneurs quittés, utilisez le drapeau -f pour filtrer en fonction de leur statut. Lorsque vous avez vérifié que vous voulez supprimer ces conteneurs, utilisez -q pour transmettre les ID à la commande docker rm.

      Lister :

      • docker ps -a -f status=exited

      Supprimer :

      • docker rm $(docker ps -a -f status=exited -q)

      Supprimer les conteneurs en utilisant plusieurs filtre

      Les filtres de Docker peuvent être combinés en répétant le drapeau filter avec une valeur supplémentaire. Il en résulte une liste de conteneurs qui remplissent l’une ou l’autre de ces conditions. Par exemple, si vous voulez supprimer tous les conteneurs marqués comme étant soit Créé (un état qui peut survenir lorsque vous exécutez un conteneur avec une commande non valide) soit Quitté, vous pouvez utiliser deux filtres :

      Lister :

      • docker ps -a -f status=exited -f status=created

      Supprimer :

      • docker rm $(docker ps -a -f status=exited -f status=created -q)

      Supprimer des conteneurs selon un modèle

      Vous pouvez trouver tous les containers qui correspondent à un modèle en utilisant une combinaison de docker ps et grep. Lorsque vous êtes satisfait de la liste que vous souhaitez supprimer, vous pouvez utiliser awk et xargs pour fournir l’ID à docker rmi. Notez que ces utilitaires ne sont pas fournis par Docker et ne sont pas nécessairement disponibles sur tous les systèmes :

      Lister :

      • docker ps -a | grep "pattern

      Supprimer :

      • docker ps -a | grep "pattern" | awk '{print $3}' | xargs docker rmi

      Arrêter et supprimer tous les conteneurs

      Vous pouvez consulter les conteneurs sur votre système avec docker ps. L’ajout du drapeau -a affichera tous les conteneurs. Lorsque vous êtes sûr de vouloir les supprimer, vous pouvez ajouter le drapeau -q pour fournir les identifiants aux commandes docker start et docker rm :

      Lister :

      Supprimer :

      • docker stop $(docker ps -a -q)
      • docker rm $(docker ps -a -q)

      Suppression de volumes

      Supprimer un ou plusieurs volumes spécifiques – Docker 1.9 et suivants

      Utilisez la commande docker volume ls pour localiser le ou les noms de volume que vous souhaitez supprimer. Ensuite, vous pouvez supprimer un ou plusieurs volumes avec la commande docker volume rm :

      Lister :

      Supprimer :

      • docker volume rm volume_name volume_name

      Supprimer des volumes en suspens – Docker 1.9 et suivants

      Étant donné que le principe des volumes est d’exister indépendamment des conteneurs, lorsqu’un conteneur est retiré, un volume n’est pas automatiquement retiré en même temps. Lorsqu’un volume existe et n’est plus connecté à aucun conteneur, on l’appelle un volume en suspens. Pour les localiser afin de confirmer que vous voulez les retirer, vous pouvez utiliser la commande docker volume ls avec un filtre pour limiter les résultats aux volumes en suspens. Lorsque vous êtes satisfait de la liste, vous pouvez tous les supprimer avec docker volume prune :

      Lister :

      • docker volume ls -f dangling=true

      Supprimer :

      Supprimer un conteneur et son volume

      Si vous avez créé un volume sans nom, il peut être supprimé en même temps que le conteneur avec le drapeau -v. Notez que cela ne fonctionne qu’avec les volumes non nommés. Lorsque le conteneur est supprimé avec succès, son ID est affiché. Notez qu’aucune référence n’est faite à la suppression du volume. S’il n’est pas nommé, il est supprimé silencieusement du système. S’il est nommé, il reste silencieusement présent.

      Supprimer :

      • docker rm -v container_name

      Conclusion

      Ce guide couvre certaines des commandes courantes utilisées pour supprimer les images, les conteneurs et les volumes avec Docker. Il existe de nombreuses autres combinaisons et drapeaux qui peuvent être utilisés avec chacun d’entre eux. Pour un guide complet sur ce qui est disponible, consultez la documentation Docker pour docker system prune, docker rmi, docker rm et docker volume rm. S’il existe des tâches courantes de nettoyage que vous souhaitez voir dans le guide, veuillez demander ou faire des suggestions dans les commentaires.



      Source link

      How To Use the MySQL BLOB Data Type to Store Images with PHP on Ubuntu 18.04


      The author selected Girls Who Code to receive a donation as part of the Write for DOnations program.

      Introduction

      A Binary Large Object (BLOB) is a MySQL data type that can store binary data such as images, multimedia, and PDF files.

      When creating applications that require a tightly-coupled database where images should be in sync with related data (for example, an employee portal, a student database, or a financial application), you might find it convenient to store images such as students’ passport photos and signatures in a MySQL database alongside other related information.

      This is where the MySQL BLOB data type comes in. This programming approach eliminates the need for creating a separate file system for storing images. The scheme also centralizes the database, making it more portable and secure because the data is isolated from the file system. Creating backups is also more seamless since you can create a single MySQL dump file that contains all your data.

      Retrieving data is faster, and when creating records you can be sure that data validation rules and referential integrity are maintained especially when using MySQL transactions.

      In this tutorial, you will use the MySQL BLOB data type to store images with PHP on Ubuntu 18.04.

      Prerequisites

      To follow along with this guide, you will need the following:

      Step 1 — Creating a Database

      You’ll start off by creating a sample database for your project. To do this, SSH in to your server and then run the following command to log in to your MySQL server as root:

      Enter the root password of your MySQL database and hit ENTER to continue.

      Then, run the following command to create a database. In this tutorial we’ll name it test_company:

      • CREATE DATABASE test_company;

      Once the database is created, you will see the following output:

      Output

      Query OK, 1 row affected (0.01 sec)

      Next, create a test_user account on the MySQL server and remember to replace PASSWORD with a strong password:

      • CREATE USER 'test_user'@'localhost' IDENTIFIED BY 'PASSWORD';

      You’ll see the following output:

      Output

      Query OK, 0 rows affected (0.01 sec)

      To grant test_user full privileges on the test_company database, run:

      • GRANT ALL PRIVILEGES ON test_company.* TO 'test_user'@'localhost';

      Make sure you get the following output:

      Output

      Query OK, 0 rows affected (0.01 sec)

      Finally, flush the privileges table in order for MySQL to reload the permissions:

      Ensure you see the following output:

      Output

      Query OK, 0 rows affected (0.01 sec)

      Now that the test_company database and test_user are ready, you’ll move on to creating a products table for storing sample products. You’ll use this table later to insert and retrieve records to demonstrate how MySQL BLOB works.

      Log out from the MySQL server:

      Then, log back in again with the credentials of the test_user that you created:

      When prompted, enter the password for the test_user and hit ENTER to continue. Next, switch to the test_company database by typing the following:

      Once the test_company database is selected, MySQL will display:

      Output

      Database changed

      Next, create a products table by running:

      • CREATE TABLE `products` (product_id BIGINT PRIMARY KEY AUTO_INCREMENT, product_name VARCHAR(50), price DOUBLE, product_image BLOB) ENGINE = InnoDB;

      This command creates a table named products. The table has four columns:

      • product_id: This column uses a BIGINT data type in order to accommodate a large list of products up to a maximum of 2⁶³-1 items. You’ve marked the column as PRIMARY KEY to uniquely identify products. In order for MySQL to handle the generation of new identifiers for inserted columns, you have used the keyword AUTO_INCREMENT.

      • product_name: This column holds the names of the products. You’ve used the VARCHAR data type since this field will generally handle alphanumerics up to a maximum of 50 characters—the limit of 50 is just a hypothetical value used for the purpose of this tutorial.

      • price: For demonstration purposes, your products table contains the price column to store the retail price of products. Since some products may have floating values (for example, 23.69, 45.36, 102.99), you’ve used the DOUBLE data type.

      • product_image: This column uses a BLOB data type to store the actual binary data of the products’ images.

      You’ve used the InnoDB storage ENGINE for the table to support a wide range of features including MySQL transactions. After executing this for creating the products table, you’ll see the following output:

      Output

      Query OK, 0 rows affected (0.03 sec)

      Log out from your MySQL server:

      You will get the following output

      Output

      Bye

      The products table is now ready to store some records including products’ images and you’ll populate it with some products in the next step.

      Step 2 — Creating PHP Scripts for Connecting and Populating the Database

      In this step, you’ll create a PHP script that will connect to the MySQL database that you created in Step 1. The script will prepare three sample products and insert them into the products table.

      To create the PHP code, open a new file with your text editor:

      • sudo nano /var/www/html/config.php

      Then, enter the following information into the file and replace PASSWORD with the test_user password that you created in Step 1:

      /var/www/html/config.php

      <?php
      
      define('DB_NAME', 'test_company');
      define('DB_USER', 'test_user');
      define('DB_PASSWORD', 'PASSWORD');
      define('DB_HOST', 'localhost');
      
      $pdo = new PDO("mysql:host=" . DB_HOST . "; dbname=" . DB_NAME, DB_USER, DB_PASSWORD);
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      
      

      Save and close the file.

      In this file, you’ve used four PHP constants to connect to the MySQL database that you created in Step 1:

      • DB_NAME : This constant holds the name of the test_company database.

      • DB_USER : This variable holds the test_user username.

      • DB_PASSWORD : This constant stores the MySQL PASSWORD of the test_user account.

      • DB_HOST: This represents the server where the database resides. In this case, you are using the localhost server.

      The following line in your file initiates a PHP Data Object (PDO) and connects to the MySQL database:

      ...
      $pdo = new PDO("mysql:host=" . DB_HOST . "; dbname=" . DB_NAME, DB_USER, DB_PASSWORD);
      ...
      

      Toward the end of the file, you’ve set a couple of PDO attributes:

      • ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION: This attribute instructs PDO to throw an exception that can be logged for debugging purposes.
      • ATTR_EMULATE_PREPARES, false: This option increases security by telling the MySQL database engine to do the prepare instead of PDO.

      You’ll include the /var/www/html/config.php file in two PHP scripts that you will create next for inserting and retrieving records respectively.

      First, create the /var/www/html/insert_products.php PHP script for inserting records to the products table:

      • sudo nano /var/www/html/insert_products.php

      Then, add the following information into the /var/www/html/insert_products.php file:

      /var/www/html/insert_products.php

      <?php
      
      require_once 'config.php';
      
      $products = [];
      
      $products[] = [
                    'product_name' => 'VIRTUAL SERVERS',
                    'price' => 5,
                    'product_image' => file_get_contents("https://i.imgur.com/VEIKbp0.png")
                    ];
      
      $products[] = [
                    'product_name' => 'MANAGED KUBERNETES',
                    'price' => 30,
                    'product_image' => file_get_contents("https://i.imgur.com/cCc9Gw9.png")
                    ];
      
      $products[] = [
                    'product_name' => 'MySQL DATABASES',
                    'price' => 15,
                    'product_image' => file_get_contents("https://i.imgur.com/UYcHkKD.png" )
                    ];
      
      $sql = "INSERT INTO products(product_name, price, product_image) VALUES (:product_name, :price, :product_image)";
      
      foreach ($products as $product) {
          $stmt = $pdo->prepare($sql);
          $stmt->execute($product);
      }
      
      echo "Records inserted successfully";
      

      Save and close the file.

      In the file, you’ve included the config.php file at the top. This is the first file you created for defining the database variables and connecting to the database. The file also initiates a PDO object and stores it in a $pdo variable.

      Next, you’ve created an array of the products’ data to be inserted into the database. Apart from the product_name and price, which are prepared as strings and numeric values respectively, the script uses PHP’s in-built file_get_contents function to read images from an external source and pass them as strings to the product_image column.

      Next, you have prepared an SQL statement and used the PHP foreach{...} statement to insert each product into the database.

      To execute the /var/www/html/insert_products.php file, run it in your browser window using the following URL. Remember to replace your-server-IP with the public IP address of your server:

      http://your-server-IP/insert_products.php
      

      After executing the file, you’ll see a success message in your browser confirming records were inserted into the database.

      A success message showing that records were inserted to database

      You have successfully inserted three records containing product images into the products table. In the next step, you’ll create a PHP script for retrieving these records and displaying them in your browser.

      Step 3 — Displaying Products’ Information From the MySQL Database

      With the products’ information and images in the database, you’re now going to code another PHP script that queries and displays the products’ information in an HTML table on your browser.

      To create the file, type the following:

      • sudo nano /var/www/html/display_products.php

      Then, enter the following information into the file:

      /var/www/html/display_products.php

      <html>
        <title>Using BLOB and MySQL</title>
        <body>
      
        <?php
      
        require_once 'config.php';
      
        $sql = "SELECT * FROM products";
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        ?>
      
        <table border = '1' align = 'center'> <caption>Products Database</caption>
          <tr>
            <th>Product Id</th>
            <th>Product Name</th>
            <th>Price</th>
            <th>Product Image</th>
          </tr>
      
        <?php
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            echo '<tr>';
            echo '<td>' . $row['product_id'] . '</td>';
            echo '<td>' . $row['product_name'] . '</td>';
            echo '<td>' . $row['price'] . '</td>';
            echo '<td>' .
            '<img src = "data:image/png;base64,' . base64_encode($row['product_image']) . '" width = "50px" height = "50px"/>'
            . '</td>';
            echo '</tr>';
        }
        ?>
      
        </table>
        </body>
      </html>
      

      Save the changes to the file and close it.

      Here you’ve again included the config.php file in order to connect to the database. Then, you have prepared and executed an SQL statement using PDO to retrieve all items from the products table using the SELECT * FROM products command.

      Next, you have created an HTML table and populated it with the products’ data using the PHP while() {...} statement. The line $row = $stmt->fetch(PDO::FETCH_ASSOC) queries the database and stores the result in the $row variable as a multi-dimensional array, which you have then displayed in an HTML table column using the $row['column_name'] syntax.

      The images from the product_image column are enclosed inside the <img src = ""> tags. You’ve used the width and height attributes to resize the images to a smaller size that can fit in the HTML table column.

      In order to convert the data held by the BLOB data type back to images, you’ve used the in-built PHP base64_encode function and the following syntax for the Data URI scheme:

      data:media_type;base64, base_64_encoded_data
      

      In this case, the image/png is the media_type and the Base64 encoded string from the product_image column is the base_64_encoded_data.

      Next, execute the display_products.php file in a web browser by typing the following address:

      http://your-server-IP/display_products.php
      

      After running the display_products.php file in your browser, you will see an HTML table with a list of products and associated images.

      List of products from MySQL database

      This confirms that the PHP script for retrieving images from MySQL is working as expected.

      Conclusion

      In this guide, you used the MySQL BLOB data type to store and display images with PHP on Ubuntu 18.04. You’ve also seen the basic advantages of storing images in a database as opposed to storing them in a file system. These include portability, security, and ease of backup. If you are building an application such as a students’ portal or employees’ database that requires information and related images to be stored together, then this technology can be of great use to you.

      For more information about the supported data types in MySQL follow the MySQL Data Types guide. If you’re interested in further content relating to MySQL and PHP, check out the following tutorials:



      Source link

      How To Optimize Docker Images for Production


      The author selected Code.org to receive a donation as part of the Write for DOnations program.

      Introduction

      In a production environment, Docker makes it easy to create, deploy, and run applications inside of containers. Containers let developers gather applications and all their core necessities and dependencies into a single package that you can turn into a Docker image and replicate. Docker images are built from Dockerfiles. The Dockerfile is a file where you define what the image will look like, what base operating system it will have, and which commands will run inside of it.

      Large Docker images can lengthen the time it takes to build and send images between clusters and cloud providers. If, for example, you have a gigabyte-sized image to push every time one of your developers triggers a build, the throughput you create on your network will add up during the CI/CD process, making your application sluggish and ultimately costing you resources. Because of this, Docker images suited for production should only have the bare necessities installed.

      There are several ways to decrease the size of Docker images to optimize for production. First off, these images don’t usually need build tools to run their applications, and so there’s no need to add them at all. By using a multi-stage build process, you can use intermediate images to compile and build the code, install dependencies, and package everything into the smallest size possible, then copy over the final version of your application to an empty image without build tools. Additionally, you can use an image with a tiny base, like Alpine Linux. Alpine is a suitable Linux distribution for production because it only has the bare necessities that your application needs to run.

      In this tutorial, you’ll optimize Docker images in a few simple steps, making them smaller, faster, and better suited for production. You’ll build images for a sample Go API in several different Docker containers, starting with Ubuntu and language-specific images, then moving on to the Alpine distribution. You will also use multi-stage builds to optimize your images for production. The end goal of this tutorial is to show the size difference between using default Ubuntu images and optimized counterparts, and to show the advantage of multi-stage builds. After reading through this tutorial, you’ll be able to apply these techniques to your own projects and CI/CD pipelines.

      Note: This tutorial uses an API written in Go as an example. This simple API will give you a clear understanding of how you would approach optimizing Go microservices with Docker images. Even though this tutorial uses a Go API, you can apply this process to almost any programming language.

      Prerequisites

      Before you start you will need:

      Step 1 — Downloading the Sample Go API

      Before optimizing your Docker image, you must first download the sample API that you will build your Docker images from. Using a simple Go API will showcase all the key steps of building and running an application inside a Docker container. This tutorial uses Go because it’s a compiled language like C++ or Java, but unlike them, has a very small footprint.

      On your server, begin by cloning the sample Go API:

      • git clone https://github.com/do-community/mux-go-api.git

      Once you have cloned the project, you will have a directory named mux-go-api on your server. Move into this directory with cd:

      This will be the home directory for your project. You will build your Docker images from this directory. Inside, you will find the source code for an API written in Go in the api.go file. Although this API is minimal and has only a few endpoints, it will be appropriate for simulating a production-ready API for the purposes of this tutorial.

      Now that you have downloaded the sample Go API, you are ready to build a base Ubuntu Docker image, against which you can compare the later, optimized Docker images.

      Step 2 — Building a Base Ubuntu Image

      For your first Docker image, it will be useful to see what it looks like when you start out with a base Ubuntu image. This will package your sample API in an environment similar to the software you're already running on your Ubuntu server. Inside the image, you will install the various packages and modules you need to run your application. You will find, however, that this process creates a rather heavy Ubuntu image that will affect build time and the code readability of your Dockerfile.

      Start by writing a Dockerfile that instructs Docker to create an Ubuntu image, install Go, and run the sample API. Make sure to create the Dockerfile in the directory of the cloned repo. If you cloned to the home directory it should be $HOME/mux-go-api.

      Make a new file called Dockerfile.ubuntu. Open it up in nano or your favorite text editor:

      • nano ~/mux-go-api/Dockerfile.ubuntu

      In this Dockerfile, you'll define an Ubuntu image and install Golang. Then you'll proceed to install the needed dependencies and build the binary. Add the following contents to Dockerfile.ubuntu:

      ~/mux-go-api/Dockerfile.ubuntu

      FROM ubuntu:18.04
      
      RUN apt-get update -y 
        && apt-get install -y git gcc make golang-1.10
      
      ENV GOROOT /usr/lib/go-1.10
      ENV PATH $GOROOT/bin:$PATH
      ENV GOPATH /root/go
      ENV APIPATH /root/go/src/api
      
      WORKDIR $APIPATH
      COPY . .
      
      RUN  
        go get -d -v 
        && go install -v 
        && go build
      
      EXPOSE 3000
      CMD ["./api"]
      

      Starting from the top, the FROM command specifies which base operating system the image will have. Then the RUN command installs the Go language during the creation of the image. ENV sets the specific environment variables the Go compiler needs in order to work properly. WORKDIR specifies the directory where we want to copy over the code, and the COPY command takes the code from the directory where Dockerfile.ubuntu is and copies it over into the image. The final RUN command installs Go dependencies needed for the source code to compile and run the API.

      Note: Using the && operators to string together RUN commands is important in optimizing Dockerfiles, because every RUN command will create a new layer, and every new layer increases the size of the final image.

      Save and exit the file. Now you can run the build command to create a Docker image from the Dockerfile you just made:

      • docker build -f Dockerfile.ubuntu -t ubuntu .

      The build command builds an image from a Dockerfile. The -f flag specifies that you want to build from the Dockerfile.ubuntu file, while -t stands for tag, meaning you're tagging it with the name ubuntu. The final dot represents the current context where Dockerfile.ubuntu is located.

      This will take a while, so feel free to take a break. Once the build is done, you'll have an Ubuntu image ready to run your API. But the final size of the image might not be ideal; anything above a few hundred MB for this API would be considered an overly large image.

      Run the following command to list all Docker images and find the size of your Ubuntu image:

      You'll see output showing the image you just created:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 61b2096f6871 33 seconds ago 636MB . . .

      As is highlighted in the output, this image has a size of 636MB for a basic Golang API, a number that may vary slightly from machine to machine. Over multiple builds, this large size will significantly affect deployment times and network throughput.

      In this section, you built an Ubuntu image with all the needed Go tools and dependencies to run the API you cloned in Step 1. In the next section, you'll use a pre-built, language-specific Docker image to simplify your Dockerfile and streamline the build process.

      Step 3 — Building a Language-Specific Base Image

      Pre-built images are ordinary base images that users have modified to include situation-specific tools. Users can then push these images to the Docker Hub image repository, allowing other users to use the shared image instead of having to write their own individual Dockerfiles. This is a common process in production situations, and you can find various pre-built images on Docker Hub for almost any use case. In this step, you'll build your sample API using a Go-specific image that already has the compiler and dependencies installed.

      With pre-built base images already containing the tools you need to build and run your app, you can cut down the build time significantly. Because you're starting with a base that has all needed tools pre-installed, you can skip adding these to your Dockerfile, making it look a lot cleaner and ultimately decreasing the build time.

      Go ahead and create another Dockerfile and name it Dockerfile.golang. Open it up in your text editor:

      • nano ~/mux-go-api/Dockerfile.golang

      This file will be significantly more concise than the previous one because it has all the Go-specific dependencies, tools, and compiler pre-installed.

      Now, add the following lines:

      ~/mux-go-api/Dockerfile.golang

      FROM golang:1.10
      
      WORKDIR /go/src/api
      COPY . .
      
      RUN 
          go get -d -v 
          && go install -v 
          && go build
      
      EXPOSE 3000
      CMD ["./api"]
      

      Starting from the top, you'll find that the FROM statement is now golang:1.10. This means Docker will fetch a pre-built Go image from Docker Hub that has all the needed Go tools already installed.

      Now, once again, build the Docker image with:

      • docker build -f Dockerfile.golang -t golang .

      Check the final size of the image with the following command:

      This will yield output similar to the following:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE golang latest eaee5f524da2 40 seconds ago 744MB . . .

      Even though the Dockerfile itself is more efficient and the build time is shorter, the total image size actually increased. The pre-built Golang image is around 744MB, a significant amount.

      This is the preferred way to build Docker images. It gives you a base image which the community has approved as the standard to use for the specified language, in this case Go. However, to make an image ready for production, you need to cut away parts that the running application does not need.

      Keep in mind that using these heavy images is fine when you are unsure about your needs. Feel free to use them both as throwaway containers as well as the base for building other images. For development or testing purposes, where you don't need to think about sending images through the network, it's perfectly fine to use heavy images. But if you want to optimize deployments, then you need to try your best to make your images as tiny as possible.

      Now that you have tested a language-specific image, you can move on to the next step, in which you will use the lightweight Alpine Linux distribution as a base image to make your Docker image lighter.

      Step 4 — Building Base Alpine Images

      One of the easiest steps to optimize your Docker images is to use smaller base images. Alpine is a lightweight Linux distribution designed for security and resource efficiency. The Alpine Docker image uses musl libc and BusyBox to stay compact, requiring no more than 8MB in a container to run. The tiny size is due to binary packages being thinned out and split, giving you more control over what you install, which keeps the environment as small and efficient as possible.

      The process of creating an Alpine image is similar to how you created the Ubuntu image in Step 2. First, create a new file called Dockerfile.alpine:

      • nano ~/mux-go-api/Dockerfile.alpine

      Now add this snippet:

      ~/mux-go-api/Dockerfile.alpine

      FROM alpine:3.8
      
      RUN apk add --no-cache 
          ca-certificates 
          git 
          gcc 
          musl-dev 
          openssl 
          go
      
      ENV GOPATH /go
      ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
      ENV APIPATH $GOPATH/src/api
      RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" "$APIPATH" && chmod -R 777 "$GOPATH"
      
      WORKDIR $APIPATH
      COPY . .
      
      RUN 
          go get -d -v 
          && go install -v 
          && go build
      
      EXPOSE 3000
      CMD ["./api"]
      

      Here you're adding the apk add command to use Alpine's package manager to install Go and all libraries it requires. As with the Ubuntu image, you need to set the environment variables as well.

      Go ahead and build the image:

      • docker build -f Dockerfile.alpine -t alpine .

      Once again, check the image size:

      You will receive output similar to the following:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest ee35a601158d 30 seconds ago 426MB . . .

      The size has gone down to around 426MB.

      The small size of the Alpine base image has reduced the final image size, but there are a few more things you can do to make it even smaller.

      Next, try using a pre-built Alpine image for Go. This will make the Dockerfile shorter, and will also cut down the size of the final image. Because the pre-built Alpine image for Go is built with Go compiled from source, its footprint is significantly smaller.

      Start by creating a new file called Dockerfile.golang-alpine:

      • nano ~/mux-go-api/Dockerfile.golang-alpine

      Add the following contents to the file:

      ~/mux-go-api/Dockerfile.golang-alpine

      FROM golang:1.10-alpine3.8
      
      RUN apk add --no-cache --update git
      
      WORKDIR /go/src/api
      COPY . .
      
      RUN go get -d -v 
        && go install -v 
        && go build
      
      EXPOSE 3000
      CMD ["./api"]
      

      The only differences between Dockerfile.golang-alpine and Dockerfile.alpine are the FROM command and the first RUN command. Now, the FROM command specifies a golang image with the 1.10-alpine3.8 tag, and RUN only has a command for installing Git. You need Git for the go get command to work in the second RUN command at the bottom of Dockerfile.golang-alpine.

      Build the image with the following command:

      • docker build -f Dockerfile.golang-alpine -t golang-alpine .

      Retrieve your list of images:

      You will receive the following output:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE golang-alpine latest 97103a8b912b 49 seconds ago 288MB

      Now the image size is down to around 288MB.

      Even though you've managed to cut down the size a lot, there's one last thing you can do to get the image ready for production. It's called a multi-stage build. By using multi-stage builds, you can use one image to build the application while using another, lighter image to package the compiled application for production, a process you will run through in the next step.

      Ideally, images that you run in production shouldn't have any build tools installed or dependencies that are redundant for the production application to run. You can remove these from the final Docker image by using multi-stage builds. This works by building the binary, or in other terms, the compiled Go application, in an intermediate container, then copying it over to an empty container that doesn't have any unnecessary dependencies.

      Start by creating another file called Dockerfile.multistage:

      • nano ~/mux-go-api/Dockerfile.multistage

      What you'll add here will be familiar. Start out by adding the exact same code as with Dockerfile.golang-alpine. But this time, also add a second image where you'll copy the binary from the first image.

      ~/mux-go-api/Dockerfile.multistage

      FROM golang:1.10-alpine3.8 AS multistage
      
      RUN apk add --no-cache --update git
      
      WORKDIR /go/src/api
      COPY . .
      
      RUN go get -d -v 
        && go install -v 
        && go build
      
      ##
      
      FROM alpine:3.8
      COPY --from=multistage /go/bin/api /go/bin/
      EXPOSE 3000
      CMD ["/go/bin/api"]
      

      Save and close the file. Here you have two FROM commands. The first is identical to Dockerfile.golang-alpine, except for having an additional AS multistage in the FROM command. This will give it a name of multistage, which you will then reference in the bottom part of the Dockerfile.multistage file. In the second FROM command, you'll take a base alpine image and COPY over the compiled Go application from the multistage image into it. This process will further cut down the size of the final image, making it ready for production.

      Run the build with the following command:

      • docker build -f Dockerfile.multistage -t prod .

      Check the image size now, after using a multi-stage build.

      You will find two new images instead of only one:

      Output

      REPOSITORY TAG IMAGE ID CREATED SIZE prod latest 82fc005abc40 38 seconds ago 11.3MB <none> <none> d7855c8f8280 38 seconds ago 294MB . . .

      The <none> image is the multistage image built with the FROM golang:1.10-alpine3.8 AS multistage command. It's only an intermediary used to build and compile the Go application, while the prod image in this context is the final image which only contains the compiled Go application.

      From an initial 744MB, you've now shaved down the image size to around 11.3MB. Keeping track of a tiny image like this and sending it over the network to your production servers will be much easier than with an image of over 700MB, and will save you significant resources in the long run.

      Conclusion

      In this tutorial, you optimized Docker images for production using different base Docker images and an intermediate image to compile and build the code. This way, you have packaged your sample API into the smallest size possible. You can use these techniques to improve build and deployment speed of your Docker applications and any CI/CD pipeline you may have.

      If you are interested in learning more about building applications with Docker, check out our How To Build a Node.js Application with Docker tutorial. For more conceptual information on optimizing containers, see Building Optimized Containers for Kubernetes.



      Source link