Author: Bian Xi

Docker Compose – Flask/Redis sample

Docker Compose - Flask/Redis sample

Files

app.py

from flask import Flask, request, jsonify
from redis import Redis

app = Flask(__name__)
redis = Redis(host="redis", db=0, socket_timeout=5, charset="utf-8", decode_responses=True)

@app.route('/', methods=['POST', 'GET'])
def index():

    if request.method == 'POST':
        name = request.json['name']
        redis.rpush('students', {'name': name})
        return jsonify({'name': name})

    if request.method == 'GET':
        return jsonify(redis.lrange('students', 0, -1))

Dockerfile

FROM python:3.7.0-alpine3.8

WORKDIR /usr/src/app

COPY requirements.txt ./

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV FLASK_APP=app.py

CMD flask run --host=0.0.0.0

Build

docker-compose build

Network

docker network ls

This will show a network named as flash-redis_default created, which used by both flash and redis containers. The containers can use service name to communicate to each other.

Use parameters and arguments

Create a file called .env

PYTHON_VERSION=3.7.0-alpine3.8
REDIS_VERSION=4.0.11-alpine
DOCKER_USER=takacsmark

In docker-compose.yml file, replace environment session with env_file: .env.txt session, then use environment variable to define argument

version: "3"

services:
  app:
    build:
      context: .
      args:
        - IMAGE_VERSION=${PYTHON_VERSION}
    image: ${DOCKER_USER}/flask-redis:1.0
    env_file: .env.txt
    ports:
      - 80:5000
    networks:
      - mynet
  redis:
    image: redis:${REDIS_VERSION}
    networks:
      - mynet
    volumes:
      - mydata:/data

networks:
  mynet:
volumes:
  mydata:

In Dockerfile use argument from docker-compose.yml file

ARG IMAGE_VERSION

FROM python:$IMAGE_VERSION

WORKDIR /usr/src/app

COPY requirements.txt ./

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV FLASK_APP=app.py

CMD flask run --host=0.0.0.0

docker and docker-compose commands

docker-compose ps
docker-compose logs
docker-compose logs -f app
docker-compose stop
docker-compose start
docker-compose restart
docker-compose kill
docker-compose top

exec

docker-compose exec redis redis-cli lrange students 0 -1
docker-compose exec app /bin/bash

run

Start a new container, but port mapping will not be applied for new container by default.

docker-compose run ls -al

Desired state

Docker compose is defining the desired state, which will update the existing containers after configuration changed if possible.

For example, update port in doctor-compose.yml file, once run docker-compose up -d again, only app server will be recreated.

Note: Don't need to destroy existing containers first before run up again.

Scale

docker-compose up --scale app=3

Note: If ports session defined, there will be conflicting of port map.

Network

In docker-compose.yml file

services:
  app:
      networks:
      - mynet

networks:
  mynet:

Then a network called <project_name>_mynet will be created.

The old network can be pruned

docker network prune

External network

Network can be defined outside of docker-compose.yml file, which indicated as external network

networks:
  outside:
    external:
      name: actual-name-of-network

volumes

docker volumes ls

In docker-compose.yml file

services:
  redis:
    volumes:
      - mydata:/data

volumes:
  mydata:

Then a volume called <project_name>_mydata will be created.

Configuration Override

Single override file

The options in docker-compose.override.yml will overwrite or extend options in docker-compose.yml.

Note: Array options will be extended.

Multiple override files

docker-compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.dev.yml up -d

Migrate to cloud

Push images to docker hub

docker-compose push

Pull and run in play with docker (PWD)

docker-compose pull
docker-compose up -d

Sample data

Add sample data into redis

curl --header "Content-Type: application/json" \
--request POST \
--data '{"name":"Bruno"}' \
http://ipxxxxxxxxx.direct.labs.play-with-docker.com/

To access the sample data

curl http://ipxxxxxxxxx.direct.labs.play-with-docker.com/

Compose file reference

https://docs.docker.com/compose/compose-file/

Note: some options are only working in swarm mode or compose mode. For example, deploy only works in swarm mode, build only works in compose mode.

References

Docker compose tutorial for beginners by example [all you need to know] (Video)
Docker compose tutorial for beginners by example [all you need to know]

Terminal bracketed paste mode

Terminal bracketed paste mode

If you got some special characters when you paste a string into terminal, if they are at beginning or end of the string, then this could be bracketed paste mode caused issue.

Bracketed paste

The bracketed paste mode is to tell terminal that those strings are not typed in, they are pasted in. This can help software implemented action correctly, for example, auto indent mode should be disabled when pasting multiple lines into editor, such as vim.

In bracketed mode

If in bracketed mode, the ^[[200~ is added at beginning of string, the ^[[201~ is appended at end of string. For example, if paste string some test, terminal's app receives following string.

^[[200~some test^[[201~

Enable bracketed mode

To enable bracketed mode, run following command

printf "\e[?2004h"

Disable bracketed mode

To disable bracketed mode, run following command

printf "\e[?2004l"

References

Bracketed Paste Mode in Terminal

SSH Proxy

SSH Proxy

When access remote servers, proxy server/jump host could be a good choice.

Two servers definition

jump_host

This is the proxy server, normally can be in the form of user@proxy_host.

target

This is the target server, has the form of target_user@target_host.

Jump host

This is the most simplest method which uses remote ssh command to login to target server. If just wants to use one SSH server to access another SSH server, run following command

ssh -t <jump_host> ssh <target>

Here -t is to create a pseudo-terminal, otherwise, the remote server could not display message because no tty can be used.

Proxy Jump

This is using SSH building proxy function.

ssh -o "ProxyJump <jump_host>" <target>

Proxy Command

This is to run an external command to build communication. For example, use nc command, and pass two parameters, %h is the target host, %p is the port.

ssh -o "ProxyCommand ssh <jump_host> nc %h %p" <target>

Use ssh client configuration

./ssh/cofig

Instead of using command, ProxyJump and ProxyCommand can be set in ssh client configuration file.

Host <connection_name>
  HostName <target_host>
  User <target_user>
  ProxyCommand ssh <jump_host> nc %h %p

For one server

Host target
  HostName 192.168.1.2
  User user1
  ProxyCommand ssh user2@proxy nc %h %p

For all servers

Host * !proxy
  HostName %h
  User target_user
  # ProxyCommand ssh proxy_user@proxy nc %h %p

/etc/ssh/ssh_config

This is the same as previous example, except it is a global setting.

References

4 ways to SSH & SCP via proxy (jump) server in Linux