Docker containers not working after deploy

2019-08-27 02:31发布

问题:

I have a set of docker containers that are generated from yaml files. These containers work ok - I can access localhost, ping http://web from the nginx container, and list the port mapping (see snippet1)

I now want to deploy them to another machine, so I used the docker commit, save, load, and run to create an image, copy the image and deploy new containers (see snippet2).

But after I deploy the containers, they don't run properly (I cannot access localhost, cannot ping http://web from the nginx container, and port mapping is empty - see snippet3)

The .yml file is in snippet4

and the nginx .conf files are in snippet5

What can be the problem?

Thanks,

Avner


EDIT:

From the responses below, I understand that instead of using "docker commit", I should build the container on the remote host using one of 2 options:

  • option1 - copy the code to the remote host and apply a modified docker-compose, and build from source using a modified docker-compose

  • option2 - create an image on local machine, push it to a docker repository, pull it from there, using a modified docker-compose

I'm trying to follow option1 (as a start), but still have problems. I filed a new post here that describes the problem

END EDIT:


snippet1 - original containers work ok

# the original containers
docker ps 
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                         NAMES
26ba325e737d        webserver_nginx      "nginx -g 'daemon of…"   3 hours ago         Up 43 minutes       0.0.0.0:80->80/tcp, 443/tcp   webserver_nginx_1
08ef8a443658        webserver_web        "flask run --host=0.…"   3 hours ago         Up 43 minutes       0.0.0.0:8000->8000/tcp        webserver_web_1
33c13a308139        webserver_postgres   "docker-entrypoint.s…"   3 hours ago         Up 43 minutes       0.0.0.0:5432->5432/tcp        webserver_postgres_1


# can access localhost
curl http://localhost:80
<!DOCTYPE html>
...


# can ping web container from the nginx container
docker exec -it webserver_nginx_1 bash
root@26ba325e737d:/# ping web
PING web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.138 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.123 ms
...


# List port mappings for the container
docker port webserver_nginx_1
80/tcp -> 0.0.0.0:80

snippet2 - deploy the containers (currently still using the deployed containers on localhost)

# create new docker images from the containers
docker commit webserver_nginx_1 webserver_nginx_image2
docker commit webserver_postgres_1 webserver_postgres_image2
docker commit webserver_web_1 webserver_web_image2

# save the docker images into .tar files
docker save webserver_nginx_image2 > /tmp/webserver_nginx_image2.tar
docker save webserver_postgres_image2 > /tmp/webserver_postgres_image2.tar
docker save webserver_web_image2 > /tmp/webserver_web_image2.tar

# load the docker images from tar files
cat /tmp/webserver_nginx_image2.tar | docker load
cat /tmp/webserver_postgres_image2.tar | docker load
cat /tmp/webserver_web_image2.tar | docker load

# Create containers from the new images
docker run -d --name webserver_web_2 webserver_web_image2
docker run -d --name webserver_postgres_2 webserver_postgres_image2
docker run -d --name webserver_nginx_2 webserver_nginx_image2


# stop the original containers and start the deployed containers
docker stop webserver_web_1 webserver_nginx_1 webserver_postgres_1
docker stop webserver_web_2 webserver_nginx_2 webserver_postgres_2
docker start webserver_web_2 webserver_nginx_2 webserver_postgres_2

snippet3 - deployed containers don't work

# the deployed containers
docker ps 
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS               NAMES
15ef8bfc0ceb        webserver_nginx_image2      "nginx -g 'daemon of…"   3 hours ago         Up 4 seconds        80/tcp, 443/tcp     webserver_nginx_2
d6d228599f81        webserver_postgres_image2   "docker-entrypoint.s…"   3 hours ago         Up 3 seconds        5432/tcp            webserver_postgres_2
a8aac280ea01        webserver_web_image2        "flask run --host=0.…"   3 hours ago         Up 4 seconds        8000/tcp            webserver_web_2


# can NOT access localhost
curl http://localhost:80
curl: (7) Failed to connect to localhost port 80: Connection refused


# can NOT ping web container from the nginx container
docker exec -it webserver_nginx_2 bash
root@15ef8bfc0ceb:/# ping web
ping: unknown host

# List port mappings for the container
docker port webserver_nginx_2
# nothing is being shown

snippet4 - the .yml files

cat /home/user/webServer/docker-compose.yml

version: '3'

services:
  web:
    restart: always
    build: ./web
    expose:
      - "8000"
    volumes:
      - /home/user/webServer/web:/home/flask/app/web
    command: /usr/local/bin/gunicorn -w 2 -t 3600 -b :8000 project:app
    depends_on:
      - postgres
    stdin_open: true
    tty: true

  nginx:
    restart: always
    build: ./nginx
    ports:
      - "80:80"
    volumes:
      - /home/user/webServer/web:/home/flask/app/web
    depends_on:
      - web

  postgres:
    restart: always
    build: ./postgresql
    volumes:
      - data1:/var/lib/postgresql
    expose:
      - "5432"

volumes:
  data1:

,

cat /home/user/webServer/docker-compose.override.yml

version: '3'

services:
  web:
    build: ./web
    ports:
      - "8000:8000"
    environment:
      - PYTHONUNBUFFERED=1
      - FLASK_APP=run.py
      - FLASK_DEBUG=1
    volumes:
      - /home/user/webServer/web:/usr/src/app/web
      - /home/user/webClient/:/usr/src/app/web/V1
    command: flask run --host=0.0.0.0 --port 8000

  nginx:
    volumes:
      - /home/user/webServer/web:/usr/src/app/web
      - /home/user/webClient/:/usr/src/app/web/V1
    depends_on:
      - web

  postgres:
    ports:
      - "5432:5432"

snippet5 - the nginx .conf files

cat /home/user/webServer/nginx/nginx.conf

# Define the user that will own and run the Nginx server
user  nginx;
# Define the number of worker processes; recommended value is the number of
# cores that are being used by your server
worker_processes  1;

# Define the location on the file system of the error log, plus the minimum
# severity to log messages for
error_log  /var/log/nginx/error.log warn;
# Define the file that will store the process ID of the main NGINX process
pid        /var/run/nginx.pid;


# events block defines the parameters that affect connection processing.
events {
    # Define the maximum number of simultaneous connections that can be opened by a worker process
    worker_connections  1024;
}


# http block defines the parameters for how NGINX should handle HTTP web traffic
http {
    # Include the file defining the list of file types that are supported by NGINX
    include       /etc/nginx/mime.types;
    # Define the default file type that is returned to the user
    default_type  text/html;

    # Define the format of log messages.
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    # Define the location of the log of access attempts to NGINX
    access_log  /var/log/nginx/access.log  main;

    # Define the parameters to optimize the delivery of static content
    sendfile        on;
    tcp_nopush     on;
    tcp_nodelay    on;

    # Define the timeout value for keep-alive connections with the client
    keepalive_timeout  65;

    # Define the usage of the gzip compression algorithm to reduce the amount of data to transmit
    #gzip  on;

    # Include additional parameters for virtual host(s)/server(s)
    include /etc/nginx/conf.d/*.conf;
}

,

cat /home/user/webServer/nginx/myapp.conf

# Define the parameters for a specific virtual host/server
server {

    # Define the server name, IP address, and/or port of the server
    listen 80;

    # Define the specified charset to the “Content-Type” response header field
    charset utf-8;

    # Configure NGINX to deliver static content from the specified folder
    location /static {
        alias /home/flask/app/web/instance;
    }

    location /foo {
        root /usr/src/app/web;
        index index5.html;
    }

    location /V1 {
        root /usr/src/app/web;
        index index.html;
    }

    # Configure NGINX to reverse proxy HTTP requests to the upstream server (Gunicorn (WSGI server))
    location / {
        root /;
        index index1.html;

        resolver 127.0.0.11;
        set $example "web:8000";
        proxy_pass http://$example;

        # Redefine the header fields that NGINX sends to the upstream server
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Define the maximum file size on file uploads
        client_max_body_size 10M;
        client_body_buffer_size 10M;


        if ($request_method = 'OPTIONS') {
           add_header 'Access-Control-Allow-Origin' '*';
           add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
           #
           # Custom headers and headers various browsers *should* be OK with but aren't
           #
           add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
           #
           # Tell client that this pre-flight info is valid for 20 days
           #
           add_header 'Access-Control-Max-Age' 1728000;
           add_header 'Content-Type' 'text/plain; charset=utf-8';
           add_header 'Content-Length' 0;
           return 204;
        }
        if ($request_method = 'POST') {
           add_header 'Access-Control-Allow-Origin' '*';
           add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
           add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
           add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
        if ($request_method = 'GET') {
           add_header 'Access-Control-Allow-Origin' '*';
           add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
           add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
           add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }

    }

}

回答1:

The way you've tried to deploy your app on another server is not how Docker recommends you to do it. You need to transfer all of your files that need to be present in order to get the application running along with a Dockerfile to build the image and a docker-compose.yml to define how each of the services of your application gets deployed. Docker has a nice document to get started with.

If your intention was to deploy the application on another server for redundancy and not to create a replica, consider using docker with swarm mode.



回答2:

You need to copy the docker-compose.yml file to the target machine (with some edits) and re-run it there. If you're not also rebuilding the images there, you need to modify the file to not include volumes: referencing a local source tree and change the build: block to reference some image:. Never run docker commit.

The docker-compose.yml file mostly consists of options equivalent to docker run options, but in a more convenient syntax. For example, when docker-compose.yml says

services:
  nginx:
    ports:
      - "80:80"

That's equivalent to a docker run -p 80:80 option, but when you later do

docker run -d --name webserver_nginx_2 webserver_nginx_image2

That option is missing. Docker Compose also implicitly creates a Docker network for you and without the equivalent docker run --net option, connectivity between containers doesn't work.

All of these options must be specified every time you docker run the container. docker commit does not persist them. In general you should never run docker commit, especially if you already have Dockerfiles for your images; in the scenario you're describing here the image that comes out of docker commit won't be any different from what you could docker build yourself, except that it will lose some details like the default CMD to run.

As the commenters suggest, the best way to run the same setup on a different machine is to set up a Docker registry (or use a public service like Docker Hub), docker push your built images there, copy only the docker-compose.yml file to the new machine, and run docker-compose up there. (Think of it like the run.sh script that launches your containers.) You have to make a couple of changes: replace the build: block with the relevant image: and delete the volumes: that reference local source code. If you need the database data this needs to be copied separately.

services:
  web:
    restart: always
    image: myapp/web
    depends_on:
      - postgres
    ports:
      - "8000:8000"
    # expose:, command:, and core environment: should be in Dockerfile
    # stdin_open: and tty: shouldn't matter for a Flask app
    # volumes: replace code in the image and you're not copying that


标签: docker