This article shares how to build redis cluster in docker environment, and shares some common knowledge of Docker in the process of building.

Prepare the mirror

For details on how to build a bin/ Ubuntu :16.04 image, see Docker Infrastructure

Build a bin/redis:5.0.7 image based on bin/ Ubuntu :16.04 and install redis-5.0.7 using the source code (download redis-5.0.7.tar.gz first). Dockerfile is as follows:

FROM bin/ubuntu:16.04 RUN apt-get update && apt install -yqq make GCC WORKDIR /var/lib COPY redis-5.0.7.tar.gz. RUN tar -xzvf redis-5.0.7.tar.gz && rm redis-5.0.7.tar.gz WORKDIR /var/lib/redis-5.0.7 RUN make installCopy the code

Build a bin/redis-server image with the following Dockerfile

FROM bin/redis:5.0.7 COPY Docker-entrypoint. sh /usr/local/bin

RUN groupadd -r redis && useradd -r -g redis redis \
&& chmod 777  /usr/local/bin/docker-entrypoint.sh

VOLUME /usr/local/redis/data/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["--port 6379"]
Copy the code

CMD and ENTRYPOINT directives are used to specify commands to run when the container is started. You can also specify the command to RUN when the container is started using the RUN command. They differ as follows

  1. In the absence of the ENTRYPOINT directive, the CMD directive can specify the default command. If a command is specified when starting the container with RUN, the CMD directive is overridden, whereas if not, the default command in CMD is executed.
  2. ENTRYPOINT directives exist. Commands specified by ENTRYPOINT cannot be overridden by RUN (unless the — ENTRYPOINT argument is used), but CMD/RUN can specify arguments (as arguments to the ENTRYPOINT specified command). Override CMD arguments if specified in RUN. If not specified, the default arguments in CMD are used.
  3. CMD and ENTRYPOINT directives can exec mode, such asENTRYPOINT ["docker-entrypoint.sh","--port 6379"], shell mode can also be used, for exampleENTRYPOINT docker-entrypoint.sh --port 6379In this case, docker will add /bin/sh -c before the specified command, which may cause some errors. It is recommended to use exec mode.

The container startup command is docker-entrypoint.sh. The default parameter is –port 6379. You can also specify parameters in the RUN command. (The RUN command is used to start the container, not the RUN command in the Dockerfile.)

Docker-entrypoint. sh is responsible for modifying the configuration and starting Redis

#! /bin/bash
mkdir -p /etc/redis/ /var/log/redis/ /usr/local/redis/data/
chown -R redis:redis /var/log/redis/ /usr/local/redis/data/

cat>>/etc/redis/redis.conf<<EOF
protected-mode no
appendonly yes
logfile /var/log/redis/redis.log
dir /usr/local/redis/data/
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
EOF

exec gosu redis redis-server  /etc/redis/redis.conf  $@
Copy the code

Exec is a built-in command of bash. Exec replaces the current shell process with the executed command, and no other commands are executed after exec. Starting Redis with exec and gosu can make redis a process with PID equal to 1 to ensure the normal operation of signals such as SIGTERM. The EXCE mode of the CMD/ENTRYPOINT directive also serves this purpose.

Start the container

Start all redis containers

for i in `seq 1 6`; do 
 	sudo docker run -d --name redis-$i bin/redis-server
done
Copy the code

Docker-entrypoint. Sh ‘–port 6379’ docker-entrypoint.

Check the process

$ sudo docker top redis-1
Copy the code

Logs can be viewed in the logs directory

$ sudo docker logs -f  redis-1
Copy the code

(Under normal use, Redis may not output logs to the foreground)

When docker container is running, it should try not to write data (otherwise, the data will be deleted after deleting the container). For applications that need to store dynamic data, such as databases, their data files should be stored in volumes. The VOLUME command is used to mount volumes. /usr/local/redis/data/ is a subdirectory of /var/lib/docker-volumes. So the docker output to the docker directory is actually saved to the host directory. If we modify a file in the host directory, Docker will know about it immediately, so we put the code file on the host (so we can modify the code) and let the Docker container read the file through the volume. Volumes can also share data by using the –volumes-from option in the run command.

Dockerfile uses the VOLUME command to mount a VOLUME that holds the AOF file of Redis, so that after the container is deleted, the file will remain in the host. You can use docker Inspect to view mounting information about Volume

"Mounts": [{"Type": "volume"."Name": "025f5fff7a31e61f8a068b7b6de38731d16b5efac7e96ac0c01892a4139e8d83"."Source": "/var/lib/docker/volumes/025f5fff7a31e61f8a068b7b6de38731d16b5efac7e96ac0c01892a4139e8d83/_data"."Destination": "/usr/local/redis/data"."Driver": "local"."Mode": ""."RW": true."Propagation": ""}].Copy the code

The run command can mount a VOLUME with the -v parameter and specify the host directory. The VOLUME command cannot do this.

sudo docker run -d  -v /home/binecy/redis/data/:/usr/local/redis/data/ bin/redis-server
Copy the code

Create the cluster

Get all the Docker container IP

$ for i in `seq 1 6`; do 
>    echo `sudo docker inspect -f '{{ .NetworkSettings.IPAddress}}'  redis-$i`
> done
172.17.0.2
172.17.0.3
172.17.0.4
172.17.0.5
172.17.0.6
172.17.0.7
Copy the code

Connect to the Redis-1 container and run the following command to create the Redis cluster

$ sudo docker exec-it redis-1 /bin/bash root$redis-cli --cluster create 172.17.0.2:6379 172.17.0.3:6379 172.17.0.4:6379 172.17.0.5:6379 172.17.0.5:6379 172.17.0.5:6379 172.17.0.7 172.17.0.6:6379:6379 - cluster - replicas of 1Copy the code

Docker network

Docker network #####bridge mode above example I use docker default network mode, namely bridge mode

Docker uses Linux’s Namespaces technology to isolate resources, such as PID Namespace to isolate processes, Mount Namespace to isolate file systems, and Network Namespace to isolate networks.

When the Docker process starts, it will automatically create a Docker0 virtual network bridge on the host. The default network segment 172.17.0.0/16 is actually a Linux Bridge, which can be understood as a software switch, and any network adapters attached to it can automatically forward data packets.

In Bridge mode, Docker creates a Network Namespace for each container. When creating a container, the container assigns an IP address from the subnet of docker0, and creates a pair of veth virtual network devices, one device in the container as the container’s network card, the other device bridge on the host docker0, can be viewed by the command BRCTL show (name is vethXXX), In this way, all containers on the host are in the same layer 2 network, so that containers and containers can communicate with each other. (But cannot communicate across hosts).

Veth, short for Virtual ETHernet, is a Virtual network device. When two virtual network adapters (Veth peers) are created, the data packets on one network adapter can be directly forwarded to the other network adapter, even though the two network adapters are not in the same namespace.

We can also customize a bridge

docker network create redis-net
Copy the code

The biggest difference between a custom bridge and the default Docker0 bridge is that a custom bridge can use –network-alias to specify network aliases for containers. Containers can communicate with each other using network aliases.

for i in `seq 1 6`; do 
 	sudo docker run -d --name  redis-$i --network redis-net --network-alias redis-$i bin/redis-server
done
Copy the code

In this way, you can ping redis-2 from redis-1 or connect to Redis-2 from redis-1 through redis-cli-h redis-2.

For distributed systems such as Mysql MGR and Zookeeper, IP information of other cluster members needs to be written into the configuration file before application startup. In this case, network aliases are suitable. (redis-cli –cluster create command cannot use network alias)

After using a customized network, you can run the following command to obtain the IP address of the Docker container

sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'  redis-1
Copy the code

Docker inspect -f supports the go template syntax, which uses the range loop to iterate over everything. NetworkSettings.Networks and take the IPAddress variable under it.

However, the created Redis cluster is accessible only to the host machine, not to external machines (non-host machines), because the Redis port in docker is not mapped to the host machine. We can also map ports with the -p argument on the run command (-p can map ports specified for EXPOSE in the Dockerfile) :

for i in `seq 1 6`; do 
 	sudo docker run -d --name redis-$i -p 6379 -p 16379 bin/redis-server
done
Copy the code

However, the external machine still cannot access the Redis cluster, because the docker container IP of the internal communication of the redis cluster (namely the IP of the redis-cli –cluster create command), when the external machine accesses the Redis cluster, The Redis Cluster will return these IP addresses to the external machine and allow the external machine to access the Redis Cluster through them, but the external machine cannot access the Docker container IP, so this method can only access the Redis Cluster on the host machine.

The -p option in the run command is implemented through the NAT protocol and can be viewed using the iptables command.

Host mode

Host mode In host mode, the container shares a Network Namespace of the host. The ports started in the container are directly the ports of the host. The container does not create Network cards and IP addresses, but uses the Network cards and IP addresses of the host

Set up the Redis cluster cluster in host mode. Start the Redis application

for port in `seq 7000 7005`; do 
    sudo docker run -d  --name redis-${port} --net=host  bin/redis-server "--port  ${port}" 
done
Copy the code

Docker-entrypoint. sh ‘–port ${port}’ is executed after the container starts.

Note that the port the container starts is the host port, so make sure that the host ports do not conflict.

Start the redis cluster from host IP192.168.0.102

$ sudo docker exec-it redis-7000 /bin/bash root$redis-cli --cluster create 192.168.0.102:7000 192.168.0.102:7002 192.168.0.102:7002 192.168.0.102:7003 192.168.0.102:7004 192.168.0.102:7005 --cluster-replicas 1Copy the code

This allows external machines to access the Redis Cluster through host IP192.168.0.102.

How to write the best Dockerfile

This article describes the Docker CMD/ENTRYPOINT, VOLUME, inspect, network and other knowledge points, basically meet our daily use of Docker.

If you think this article is good, welcome to pay attention to my wechat public number, your attention is my motivation!