Afenioux's Blog page

3am; darkness; Maintenance window closing. Safety net: rollback.

FRnOG33 - How to put a bird on a docker container
 on arista?

Written by Arnaud no comments

This is the presentation I made at FRnOG #33 to explain how we virtualized our route-server services at with BIRD, docker on arista EOS :

Keywords are : #Docker #Arista #BIRD #route-server #NFV #SDN #bingo!

(Scripts and details below)

Run the docker image

•Pull the image and run itright here, right now!
•Docker is supported on Arista EOS from 4.20.1F and onwards

bash sudo su
service docker start

  Starting docker (via systemctl):       [  OK  ]
docker run -d -p 179:179 -v /mnt/flash/docker/bird:/etc/bird:rw --name rs  --memory 512m --memory-swap 512m --cpus 1.1 afenioux/bird
  Unable to find image 'afenioux/bird:latest' locally
  latest: Pulling from afenioux/bird
docker ps
  CONTAINER ID    IMAGE            COMMAND                  CREATED           STATUS          PORTS          NAMES
  176ce20f5fa1    afenioux/bird    "/bin/sh -c 'bird -d'"   20 seconds ago    Up 19 second    179            rs
docker logs rs
  2019-07-12 15:27:37 <INFO> Started
docker exec -it rs birdc show protocols
BIRD 2.0.4 ready.
Name       Proto      Table      State  Since         Info
device1    Device     ---        up     2019-07-12 15:27:43
iBGP       BGP        ---        up     2019-07-12 15:27:56  Established
iBGP_v6    BGP        ---        up     2019-07-12 15:28:43  Established


Build and deploy an image yourself 

Multi-stage image based on debian:stable : 132MB

docker build -t --build-arg BIRDV=2.0.4 .
  Sending build context to Docker daemon  3.584kB
  Step 1/19 : FROM debian:stable AS compiler
     ---> 22f4c938cdc8
  Successfully built 3bf87da26f2c
  Successfully tagged
docker images
    REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE   2.0.4               3bf87da26f2c        28 seconds ago      132MB
docker history
  IMAGE               CREATED              CREATED BY                                      SIZE
  3bf87da26f2c        About a minute ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "bird…   0B
  8183c946e908        About a minute ago   |1 BIRDV=2.0.4 /bin/sh -c apt-get install -y…   6.96MB
  df609b80e3a7        About a minute ago   |1 BIRDV=2.0.4 /bin/sh -c echo $TZ > /etc/ti…   1.46MB
  05ecdc4530b2        About a minute ago   /bin/sh -c #(nop)  ENV TZ=Europe/Paris          0B
  b1cbdcc1aa18        About a minute ago   |1 BIRDV=2.0.4 /bin/sh -c mkdir /etc/bird /r…   0B
  539cf16c5236        About a minute ago   /bin/sh -c #(nop) COPY multi:dc6b1122ade7326…   4.48MB
  dd51f8b7b6fd        2 months ago         /bin/sh -c #(nop)  ARG BIRDV=2.0.4              0B
  c3a3916906fa        2 months ago         /bin/sh -c apt-get update && apt-get install…   18.1MB
  22f4c938cdc8        3 months ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
  <missing>           3 months ago         /bin/sh -c #(nop) ADD file:d891105338b1a0ab1…   101MB
docker login
docker push  

  2.0.4: digest: sha256:001b1b05a66e815cc90f369fa43647bff5b9a450f09da1ba10c4020413e4bf72 size: 1580


Create a registry (and enable IPv6…) 

On the registry VM :

curl -fsSL | sudo apt-key add -
echo "deb stretch stable" > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install docker-ce docker-ce-cli

docker run --entrypoint htpasswd registry:2 -Bbn the_user the_password >> /etc/docker/auth/htpasswd
docker run -d -p 80 --restart=always --name registry -v /etc/docker/auth:/auth \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \

On the client (Docker host) :

    "ipv6": true,
    "fixed-cidr-v6": "2001:db8:1::/64"

docker login


Port 179 is already used by Rib on EOS. Instead of publishing the port (docker run -p 179) we will use iptable to do Destination NAT (as Docker does anyway) and set the IP of the container manually.
The Rib BGP daemon from EOS is local, so it can’t reach $IP_RS, but you can locally peer with the IP even if port 179 isn’t published (same for IPv6).

interface loopback 1
  description IP_RS for Docker
  ip   address ${IP_RS}/32
  ipv6 address ${IP6_RS}/128

docker network create --subnet= --ipv6 --subnet=fd00:172:16::/64 hopusnet
docker run -d -v /mnt/flash/docker/bird:/etc/bird --name rs --hostname rs --memory 512m \
--cpus 1.1 --net hopusnet --ip --ip6 fd00:172:16::2$BIRD_VER

iptables  -t nat -I PREROUTING --dst ${IP_RS}/32   -p tcp --dport 179 -j DNAT --to
ip6tables -t nat -I PREROUTING --dst ${IP6_RS}/128 -p tcp --dport 179 -j DNAT --to fd00:172:16::2


Wanna SDN?

Scheduling an event-handler is king of SDN, right?

conf session rs
schedule refresh-rs-config at 11:00:00 interval 1440 timeout 60 max-log-files 7 command bash /mnt/flash/docker/

event-handler docker-start
   trigger on-boot
   action bash /mnt/flash/docker/
   delay 480
   timeout 120

#! /usr/bin/bash
# Written by Arnaud Fenioux
# Start docker and the route-server container at startup
# version 1.1

# Edit the lines below :
# Do not edit after this line, unless...

BIN=$(echo $0 | awk -F '/' '{print $NF}')
function print_log {
        echo "$BIN: $1"
        FastCli -p5 -c "send log message $BIN: $1"

print_log "Copying /mnt/flash/docker/daemon.json to /etc/docker..."
if [ ! -d "/etc/docker" ]; then
    mkdir /etc/docker
cp /mnt/flash/docker/daemon.json /etc/docker

print_log "Starting docker..."
service docker start

print_log "Signing in to registry..."
docker login -u <user> -p <password> registry.fqdn

print_log "Creating network... "
docker network create --subnet= --ipv6 --subnet=fd00:172:16::/64 mynet

print_log "Starting RS container..."
docker run -d -v /mnt/flash/docker/bird-rs:/etc/bird --name rs --hostname rs --memory 512m --cpus 1.1 --net mynet --ip --ip6 fd00:172:16::2 registry.fqdn/bird:$BIRD_VER

print_log "Adding ip(6)tables rules to RS container... "
iptables  -t nat -I PREROUTING --dst ${IP_RS}/32   -p tcp --dport 179 -j DNAT --to
ip6tables -t nat -I PREROUTING --dst ${IP6_RS}/128 -p tcp --dport 179 -j DNAT --to fd00:172:16::2

print_log "All done!"
exit 0

#! /usr/bin/bash
# Written by Arnaud Fenioux
# Get configuration file for route-servers and reload bird
# version 1.1


BIN=$(echo $0 | awk -F '/' '{print $NF}')
function print_log {
        echo "$BIN: $1"
        FastCli -p5 -c "send log message $BIN: $1"

function exit_error {
        mv $BIRD_CONF ${BIRD_CONF}.fail
        [[ -e ${BIRD_CONF}.last ]] && mv ${BIRD_CONF}.last $BIRD_CONF
        print_log "Exiting on error : $1"
        exit 1

function exit_ok {
    [[ -e ${BIRD_CONF}.last ]] && rm ${BIRD_CONF}.last
    print_log "Terminated with success!"
    exit 0

print_log "Started"
[[ -e $BIRD_CONF ]] && cp $BIRD_CONF ${BIRD_CONF}.last

#fetch_file http://hostname/$HOSTNAME -o $BIRD_CONF
#The default timeout (-T) is 900 second.
#The default is to retry 20 times (-t).
wget -T 4 -t 3 -q -O $BIRD_CONF http://hostname/$HOSTNAME
[[ $? -ne 0 ]] && exit_error "Can not fetch file"

# Checking that the file has (has not) expected lines
grep -q "Error:" $BIRD_CONF && exit_error "Bad config file (Error)"
grep -q "That's all folks!" $BIRD_CONF || exit_error "Bad config file (No EOF)"

# Same files no need to reload
diff -q -I "# Time is" $BIRD_CONF ${BIRD_CONF}.last && exit_ok

# New config, reload needed
print_log "Checking and reloading bird config"
docker exec rs birdc "configure check" | grep -q "Configuration OK"
[[ $? -ne 0 ]] && exit_error "Configuration check failed"

docker exec rs birdc "configure soft"
[[ $? -ne 0 ]] && exit_error "Configuration reload failed"


Comments are closed.

Rss feed of the article's comments