Multi-arch build, what about GitLab CI?

Following the previous article where we saw how to build multi arch images using GitHub Actions, we will now show how to do the same thing using another CI. In this article, we’ll show how to use GitLab CI, which is part of the GitLab.

To start building your image with GitLab CI, you will first need to create a .gitlab-ci.yml file at the root of your repository, commit it and push it.

image: docker:stable
variables:  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2
services:
  – docker:dind
build:
  stage: build
  script:
    – docker version

This should result in a build output that shows the version of the Docker CLI and Engine: 

We will now install Docker buildx. Because GitLabCI runs everything in containers and uses any image you want to start this container, we can use one with buildx preinstalled, like the one we used for CircleCI. And as for CircleCI, we need to start a builder instance.

image: jdrouet/docker-with-buildx:stable
variables:  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2
services:
  – docker:dind
build:
  stage: build
  script:
    – docker buildx create –use
    – docker buildx build –platform linux/arm/v7,linux/arm64/v8,linux/amd64 –tag your-username/multiarch-example:gitlab .

And that’s it, your image will now be built for both ARM and x86 platforms.

The last step is now to store the image on the Docker Hub. To do so we’ll need an access token from Docker Hub to get write access.

Once you created it, you’ll have to set in your project CI/CD settings in the Variables section.

We can then add  DOCKER_USERNAME and DOCKER_PASSWORD variables to GitLab CI so that we can login to push our images.

Once this is done, you can add the login step and the –push option to the buildx command as follows.

build:
  stage: build
  script:
    – docker login -u “$DOCKER_USERNAME” -p “$DOCKER_PASSWORD”
    – docker buildx create –use
    – docker buildx build –push –platform linux/arm/v7,linux/arm64/v8,linux/386,linux/amd64 –tag your-username/multiarch-example:gitlab .

And voila, you can now create a multi arch image each time you make a change in your codebase.
The post Multi-arch build, what about GitLab CI? appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Containerized Python Development – Part 2

This is the second part of the blog post series on how to containerize our Python development. In part 1, we have already shown how to containerize a Python service and the best practices for it. In this part, we discuss how to set up and wire other components to a containerized Python service. We show a good way to organize project files and data and how to manage the overall project configuration with Docker Compose. We also cover the best practices for writing Compose files for speeding up our containerized development process.

Managing Project Configuration with Docker Compose

Let’s take as an example an application for which we separate its functionality in three-tiers following a microservice architecture. This is a pretty common architecture for multi-service applications. Our example application consists of:

a UI tier – running on an nginx servicea logic tier – the Python component we focus ona data tier – we use a mysql database to store some data we need in the logic tier

The reason for splitting an application into tiers is that we can easily modify or add new ones without having to rework the entire project.

A good way to structure the project files is to isolate the file and configurations for each service. We can easily do this by having a dedicated directory per service inside the project one. This is very useful to have a clean view of the components and to easily containerize each service. It also helps in manipulating service specific files without having to worry that we could modify by mistake other service files.

For our example application, we have the following directories:

Project
├─── web
└─── app└─── db

We have already covered how to containerize a Python component in the first part of this blog post series.  Same applies for the other project components but we skip the details for them as we can easily access samples implementing the structure we discuss here. The nginx-flask-mysql example provided by the awesome-compose repository is one of them. 

This is the updated Project structure with the Dockerfile in place. Assume we have a similar setup for the web and db components.

Project
├─── web
├─── app
│ ├─── Dockerfile
│ ├─── requirements.txt
│ └─── src
│ └─── server.py
└─── db

We could now start the containers manually for all our containerized project components. However, to make them communicate we have to manually handle the network creation and attach the containers to it. This is fairly complicated and it would take precious development time if we need to do it frequently.

Here is where Docker Compose offers a very easy way of coordinating containers and spinning up and taking down services in our local environment. For this, all we need to do is write a Compose file containing the configuration for our project’s services. Once we have it, we can get the project running with a single command.

Compose file

Let’s see what is the structure of the Compose files and how we can manage the project services with it.

Below is a sample file for our project. As you can see we define a list of services. In  the db section we specify the base image directly as we don’t have any particular configuration to apply to it. Meanwhile our web and app service are going to have the image built from their Dockerfiles. According to where we can get the service image we can either set the build or the image field. The build field requires a path with a Dockerfile inside.

docker-compose.yamlversion: “3.7”
services:  db:    image: mysql:8.0.19    command: ‘–default-authentication-plugin=mysql_native_password’
    restart: always
    environment:
      – MYSQL_DATABASE=example
      – MYSQL_ROOT_PASSWORD=password  app:
    build: app
    restart: always
  web:
    build: web
    restart: always
    ports:
      – 80:80

To initialize the database we can pass environment variables with the DB name and password while for our web service we map the container port to the localhost in order to be able to access the web interface of our project.

Let’s see how to deploy the project with Docker Compose. 

All we need to do now is to place the docker-compose.yaml at the root directory of the project and then issue the command for deployment with docker-compose.

Project├─── docker-compose.yaml
├─── web
├─── app
└─── db

Docker Compose is going to take care of pulling the mysql image from Docker Hub and launching the db container while for our web and app service, it builds the images locally and then runs the containers from them. It also takes care of creating a default network and placing all containers in it so that they can reach each other.

All this is triggered with only one command.

$ docker-compose up -d Creating network “project_default” with the default driver Pulling db (mysql:8.0.19)… … Status: Downloaded newer image for mysql:8.0.19 Building app Step 1/6 : FROM python:3.8 —> 7f5b6ccd03e9 Step 2/6 : WORKDIR /code —> Using cache —> c347603a917d Step 3/6 : COPY requirements.txt . —> fa9a504e43ac Step 4/6 : RUN pip install -r requirements.txt —> Running in f0e93a88adb1 Collecting Flask==1.1.1 … Successfully tagged project_app:latest WARNING: Image for service app was built because it did not already exist. To rebuild this image you must use docker-compose build or docker-compose up –build. Building web Step 1/3 : FROM nginx:1.13-alpine 1.13-alpine: Pulling from library/nginx … Status: Downloaded newer image for nginx:1.13-alpine —> ebe2c7c61055 Step 2/3 : COPY nginx.conf /etc/nginx/nginx.conf —> a3b2a7c8853c Step 3/3 : COPY index.html /usr/share/nginx/html/index.html —> 9a0713a65fd6 Successfully built 9a0713a65fd6 Successfully tagged project_web:latest Creating project_web_1 … done Creating project_db_1 … done Creating project_app_1 … done

Check the running containers:

$ docker-compose ps  Name         Command                        State  Ports
————————————————————————-
project_app_1  /bin/sh -c python server.py    Up
project_db_1   docker-entrypoint.sh –def … Up     3306/tcp, 33060/tcp
project_web_1  nginx -g daemon off;           Up     0.0.0.0:80->80/tcp

To stop and remove all project containers run:

$ docker-compose downStopping project_db_1 … done
Stopping project_web_1 … done
Stopping project_app_1 … done
Removing project_db_1 … done
Removing project_web_1 … done
Removing project_app_1 … done
Removing network project-default

To rebuild images we can run a build and then an up command to update the state of the project containers:

$ docker-compose build$ docker-compose up -d

As we can see, it is quite easy to manage the lifecycle of the project containers with docker-compose.

Best practices for writing Compose files

Let us analyse the Compose file and see how we can optimise it by following best practices for writing Compose files.

Network separation

When we have several containers we need to control how to wire them together. We need to keep in mind that, as we do not set any network in the compose file, all our containers will end in the same default network.

This may not be a good thing if we want only our Python service to be able to reach the database. To address this issue, in the compose file we can actually define separate networks for each pair of components. In this case the web component won’t be able to access the DB.

Docker Volumes

Every time we take down our containers, we remove them and therefore lose the data we stored in previous sessions. To avoid that and persist DB data between different containers, we can exploit named volumes. For this, we simply define a named volume in the Compose file and specify a mount point for it in the db service as shown below:

version: “3.7”
services:  db:    image: mysql:8.0.19    command: ‘–default-authentication-plugin=mysql_native_password’
    restart: always    volumes:      – db-data:/var/lib/mysql    networks:      – backend-network
    environment:
      – MYSQL_DATABASE=example
      – MYSQL_ROOT_PASSWORD=password  app:
    build: app
    restart: always    networks:      – backend-network      – frontend-network
  web:
    build: web
    restart: always
    ports:
      – 80:80    networks:      – frontend-networkvolumes:
  db-data:
networks:
  backend-network:
  frontend-network:

 We can explicitly remove the named volumes on docker-compose down if we want.

Docker Secrets

As we can observe in the Compose file, we set the db password in plain text. To avoid this, we can exploit docker secrets to have the password stored and share it securely with the services that need it. We can define secrets and reference them in services as below. The password is being stored locally in the project/db/password.txt file and mounted in the containers under /run/secrets/<secret-name>.

version: “3.7”
services:  db:    image: mysql:8.0.19    command: ‘–default-authentication-plugin=mysql_native_password’
    restart: always    secrets:      – db-password    volumes:      – db-data:/var/lib/mysql    networks:      – backend-network
    environment:
      – MYSQL_DATABASE=example
      – MYSQL_ROOT_PASSWORD=/run/secrets/db-password  app:
    build: app
    restart: always    secrets:      – db-password    networks:      – backend-network      – frontend-network
  web:
    build: web
    restart: always
    ports:
      – 80:80    networks:      – frontend-networkvolumes:
  db-data:secrets:
  db-password:
    file: db/password.txt
networks:
  backend-network:
  frontend-network:

We have now a well defined Compose file for our project that follows best practices. An example application exercising all the aspects we discussed can be found here.

What’s next?

This blog post showed how to set up a container-based multi-service project where a Python service is wired to other services and how to deploy it locally with Docker Compose.

In the next and final part of this series, we show how to update and debug the containerized Python component.

Resources

Project samplehttps://github.com/aiordache/demos/tree/master/dockercon2020-demoDocker Compose https://docs.docker.com/compose/Project skeleton samples  https://github.com/docker/awesome-compose
The post Containerized Python Development – Part 2 appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Top Questions for Getting Started with Docker

Does Docker run on Windows?

Yes. Docker is available for Windows, MacOS and Linux. Here are the download links:

Docker Desktop for WindowsDocker Desktop for MacLinux

What is the difference between Virtual Machines (VM) and Containers?

This is a great question and I get this one a lot. The simplest way I can explain the differences between Virtual Machines and Containers is that a VM virtualizes the hardware and a Container “virtualizes” the OS. 

If you take a look at the image above, you can see that there are multiple Operating Systems running when using Virtual Machine technology. Which produces a huge difference in start up times and various other constraints and overhead when installing and maintaining a full blow operating system. Also, with VMs, you can run different flavors of operating systems. For example, I can run Windows 10 and a Linux distribution on the same hardware at the same time. Now let’s take a look at the image for Docker Containers.

As you can see in this image, we only have one Host Operating System installed on our infrastructure. Docker sits “on top” of the host operating system. Each application is then bundled in an image that contains all the configuration, libraries, files and executables the application needs to run.

At the core of the technology, containers are just an operating system process that is run by the OS but with restrictions on what files and other resources they can consume and have access to such as CPU and networking.

Since containers use features of the Host Operating System and therefore share the kernel, they need to be created for that operating system. So, for example, you can not run a container that contains linux binaries on Windows or vice versa.

This is just the basics and of course the technical details can be a little more complicated. But if you understand these basic concepts, you’ll have a good foundation of the difference between Virtual Machines and Containers.

What is the difference between an Image and a Container?

This is another very common question that is asked. I believe some of the confusion stems from the fact that we sometimes interchange these terms when talking about containers. I know I’ve been guilty of it.

An image is a template that is used by Docker to create your running Container. To define an image you create a Dockerfile. When Docker reads and executes the commands inside of your Dockerfile, the result is an image that then can be run “inside a container.”

A container, in simple terms, is a running image. You can run multiple instances of your image and you can create, start and stop them as well as connect them to other containers using networks.

What is the difference between Docker and Kubernetes?

I believe the confusion between the two stems from the development community talking as if these two are the same concepts. They are not.

Kubernetes is an orchestrator and Docker is a platform from building, shipping and running containers. Docker, in and of itself, does not handle orchestration. 

Container Orchestration, in simple terms, is the process of managing and scheduling the running of containers across nodes that the orchestrator manages. 

So generally speaking, Docker runs one instance of a container as a unit. You can run multiple containers of the same image, but Docker will not manage them as a unit.

To manage multiple containers as a unit, you would use an Orchestrator. Kubernetes is a container orchestrator. As well is AWS ECS and Azure ACI.

Why can’t I connect to my web application running in a container?

By default, containers are secure and isolated from outside network traffic – they do not expose any of its ports by default. Therefore if you want to be able to handle traffic coming from outside the container, you need to expose the port your container is listening on. For web applications this is typically port 80 or 443.

To expose a port when running a container, you can pass the –publish or -p flag. 

For example:

$ docker run -p 80:80 nginx

This will run an Nginx container and publish port 80 to the outside world.

You can read all about Docker Networking in our documentation.

How do I run multiple applications in one container?

This is a very common question that I get from folks that are coming from a Virtual Machine background. The reason being is that when working with VMs, we can think of our application as owning the whole operating system and therefore can create multiple processes or runtimes.

When working with containers, it is best practice to map one process to one container for various architectural reasons that we do not have the space to discuss here. But the biggest reason to run one process inside a container is in respect to the tried and true KISS principle. Keep It Simple Simon. 

When your containers have one process, they can focus on doing one thing and one thing only. This allows you to scale up and down relatively easily.

Stay tuned to this blog and my twitter handle (@pmckee) for more content on how to design and build applications with containers and microservices.

How do I persist data when running a container?

Containers are immutable and you should not write data into your container that you would like to be persisted after that container stops running. You want to think about containers as unchangeable processes that could stop running at any moment and be replaced by another very easily.

So, with that said, how do we write data and have a container use it at runtime or write data at runtime that can be persisted. This is where volumes come into play.

Volumes are the preferred mechanism to write and read persistent data. Volumes are managed by Docker and can be moved, copied and managed outside of containers.

For local development, I prefer to use bind mounts to access source code outside of my development container.

For an excellent overview of storage and specifics around volumes and bind mounts, please checkout our documentation on Storage.

Conclusion

These are just some of the common questions I get from people new to Docker. If you want to read more common questions and answers, check out our FAQ in our documentation.

Also, please feel free to connect on twitter (@pmckee) and ask questions if you like.
The post Top Questions for Getting Started with Docker appeared first on Docker Blog.
Quelle: https://blog.docker.com/feed/

Kubernetes Tips: Backup and Restore Etcd

medium.com – Launch a VM on a cloud provider There are many choices out there. Some of my favorites ones are DigitalOcean, Civo, and Scaleway. Also, we need to set up an ssh access to this machine using an ssh ke…
Quelle: news.kubernauts.io