快速入门

Images and containers

A container is launched by running an image. An image is an executable package that includes everything needed to run an application—​the code, a runtime, libraries, environment variables, and configuration files.

A container is a runtime instance of an image—​what the image becomes in memory when executed (that is, an image with state, or a user process). You can see a list of your running containers with the command, docker ps, just as you would in Linux.

Containers and virtual machines

A container runs natively on Linux and shares the kernel of the host machine with other containers. It runs a discrete process, taking no more memory than any other executable, making it lightweight.

By contrast, a virtual machine (VM) runs a full-blown “guest” operating system with virtual access to host resources through a hypervisor. In general, VMs provide an environment with more resources than most applications need.

container
Figure 1. container
virtual machine
Figure 2. virtual machine
# 查看 docker 版本,版本的简要信息
docker --version

# 查看 docker 版本详细信息
docker version

# 查看 docker 基本信息,挺详细
# Display system-wide information
docker info

# 运行 image
docker run hello-world

# 查看已经下载的 image
docker image ls

# 查看所有的 container(包含已经执行完成的)
docker container ls --all


## List Docker CLI commands
docker
docker container --help

## Display Docker version and info
docker --version
docker version
docker info

## Execute Docker image
docker run hello-world

## List Docker images
docker image ls

## List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls --all
docker container ls -aq

Dockerfile

Dockerfile defines what goes on in the environment inside your container. Access to resources like networking interfaces and disk drives is virtualized inside this environment, which is isolated from the rest of your system, so you need to map ports to the outside world, and be specific about what files you want to “copy in” to that environment.

Unresolved include directive in modules/ROOT/pages/get-started.adoc - include::example$01-get-started/Dockerfile[]
docker build --tag=01-friendlyhello .

docker image ls
Troubleshooting Tips
  1. Proxy server settings

    # Set proxy server, replace host:port with values for your servers
    ENV http_proxy host:port
    ENV https_proxy host:port
  2. DNS settings

    /etc/docker/daemon.json
    {
      "dns": ["your_dns_address", "8.8.8.8"]
    }
    sudo service docker restart
docker run -p 4000:80 01-friendlyhello

# 后台运行
docker run -d -p 4000:80 01-friendlyhello

docker container ls

# 停止指定容器
docker container stop <ContainerId>

# 登录
docker login

# 给指定 image 打 tag
docker tag image username/repository:tag
docker tag 01-friendlyhello diguage/01-get-started:part2

docker image ls

# Publish the image
docker push username/repository:tag
docker push diguage/01-get-started:part2

# Pull and run the image from the remote repository
docker run -p 4000:80 username/repository:tag

A registry is a collection of repositories, and a repository is a collection of images—sort of like a GitHub repository, except the code is already built.

No matter where docker run executes, it pulls your image, along with Python and all the dependencies from requirements.txt, and runs your code.

Compose

TODO:这部分回头使用 Kubernetes 相关内容重做一遍。

Services are really just “containers in production.” A service only runs one image, but it codifies the way that image runs—what ports it should use, how many replicas of the container should run so the service has the capacity it needs, and so on.

version: "3"
services:
  web:
    image: diguage/01-get-started:part2
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet
networks:
  webnet:
docker swarm init

docker stack deploy -c docker-compose.yml getstartedlab

docker service ls

# view all services associated with the getstartedlab stack:
docker stack services getstartedlab

# List the tasks for your service:
docker service ps getstartedlab_web

# 仅仅列出 Container ID
docker container ls -q

# 查看状态
docker stack ps getstartedlab

# Scale the app: 修改副本数量。
docker stack deploy -c docker-compose.yml getstartedlab
# 扩容的时候为什么要杀掉原来的 container?有业务正在处理的节点是怎么处理的?

# Take the app down
docker stack rm getstartedlab

# Take down the swarm.
docker swarm leave --force

A single container running in a service is called a task.

  1. 使用 docker service ps getstartedlab_webdocker container ls -q 中输出的 ID,为什么不同?有何关系?

    ??

with each request, one of the 5 tasks is chosen, in a round-robin fashion, to respond.

Swarm

  1. swarm

  2. swarm manager

  3. node

  4. worker

  5. swarm mode

# 创建 machine
docker-machine create --driver virtualbox myvm1
docker-machine create --driver virtualbox myvm2


docker-machine ls

# 设置 manager 节点
docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"
# 输出时,会含有如下命令
docker swarm join --token SWMTKN-1-5dbcodziijckk71tyfayg7ihm4tul2q57974xnf7akx4jmi6qy-6hlxao9pt2bi8as94k4uysqn0 192.168.99.100:2377

# 这里的 Token 是由上面生成的。
docker-machine ssh myvm2 "docker swarm join --token SWMTKN-1-5dbcodziijckk71tyfayg7ihm4tul2q57974xnf7akx4jmi6qy-6hlxao9pt2bi8as94k4uysqn0 192.168.99.100:2377"

# Run `docker node ls` on the manager to view the nodes in this swarm:
docker-machine ssh myvm1 "docker node ls"

# TODO  如何离开?
// If you want to start over, you can run docker swarm leave from each node. 这句话怎么理解?
// docker-machine ssh myvm1 "docker swarm leave"

# 配置
$ docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/diguage/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell:
# eval $(docker-machine env myvm1)

# 执行这条命令配置 Shell
eval $(docker-machine env myvm1)

# 现在 myvm1 被激活了
docker-machine ls

# 部署应用(上文中的端口号是 4000:80,这里保持不变。官方文档中漏提了需要修改端口号。)
docker stack deploy -c docker-compose.yml getstartedlab

# 如果成功的话,这可以也看到 副本集 分子和分母相等。
docker service ls

# 访问
curl http://192.168.99.100:4000
# 每次 `docker-machine create` IP 地址会增加

# 删除
docker stack rm getstartedlab

# 清除配置
eval $(docker-machine env -u)

# 启动
docker-machine start <machine-name>

# 删除
docker-machine rm <machine-name>
管理永远是 2377 端口,
ingress 路由
Figure 3. ingress 路由

这里出了个问题,排除思路:

  1. 为了方便下面的命令执行,先配置 docker-macine

    1. 执行 docker-machine env myvm1

      $ docker-machine env myvm1
      export DOCKER_TLS_VERIFY="1"
      export DOCKER_HOST="tcp://192.168.99.102:2376"
      export DOCKER_CERT_PATH="/Users/diguage/.docker/machine/machines/myvm1"
      export DOCKER_MACHINE_NAME="myvm1"
      # Run this command to configure your shell:
      # eval $(docker-machine env myvm1)
    2. 执行最后一句命令

      $ eval $(docker-machine env myvm1)
  2. 通过 docker-machine ls 查看机器 IP

    $ docker-machine ls
    NAME    ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER     ERRORS
    myvm1   *        virtualbox   Running   tcp://192.168.99.102:2376           v18.09.3
    myvm2   -        virtualbox   Running   tcp://192.168.99.103:2376           v18.09.3
  3. 获得机器 IP 后,测试网络是否通

    $ ping 192.168.99.102
    PING 192.168.99.102 (192.168.99.102): 56 data bytes
    64 bytes from 192.168.99.102: icmp_seq=0 ttl=64 time=0.294 ms
    64 bytes from 192.168.99.102: icmp_seq=1 ttl=64 time=0.256 ms
    64 bytes from 192.168.99.102: icmp_seq=2 ttl=64 time=0.222 ms
    64 bytes from 192.168.99.102: icmp_seq=3 ttl=64 time=0.405 ms
  4. 由于这是个 Web 服务,则可以通过 curl http://192.168.99.102:4000 查看是否正常。如果不能正常访问,则继续排除。

  5. 网络连通是 OK 的话,查看端口是否 OK,两个方式

    1. 使用 netstat -nl | grep 4000 查看

      $ netstat -nl | grep 4000
      tcp4       0      0  192.168.99.1.56411     192.168.99.103.4000    ESTABLISHED (1)
      tcp4       0      0  192.168.99.1.56393     192.168.99.102.4000    TIME_WAIT
      1 如果没有相应的输出,则说明有问题。
    2. 使用 telnet 192.168.99.102 4000

      $ telnet 192.168.99.102 4000
      Trying 192.168.99.102... (1)
      Connected to 192.168.99.102.
      Escape character is '^]'.
      1 如果端口有问题,这里直接就是提示 Connection refused 拒绝访问。
  6. 通过 docker node ls 检查节点的状态

    $ docker node ls
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
    mz2uqy5vjvju068uprw67z1ph *   myvm1               Ready               Active              Leader              18.09.3
    qww7x5a3836hnc8d4zx9kih4t     myvm2               Ready               Active                                  18.09.3
  7. 通过 docker stack ps getstartedlab 查看服务的状态

    $ docker stack ps getstartedlab
    ID                  NAME                      IMAGE                          NODE                DESIRED STATE       CURRENT STATE             ERROR               PORTS
    ndbmgp8wlvp0        getstartedlab_web.1       diguage/01-get-started:part2   myvm1               Running             Running 27 minutes ago (1)
    2m1aqlr4m5i6         \_ getstartedlab_web.1   diguage/01-get-started:part2   myvm1               Shutdown            Shutdown 27 minutes ago
    5xr4nmwo2ffd         \_ getstartedlab_web.1   diguage/01-get-started:part2   myvm1               Shutdown            Shutdown 28 minutes ago
    kxrtfmlkku1l         \_ getstartedlab_web.1   diguage/01-get-started:part2   myvm2               Shutdown            Shutdown 30 minutes ago
    jafp5uppesjv        getstartedlab_web.2       diguage/01-get-started:part2   myvm2               Running             Running 26 minutes ago
    nepxly7zcxss         \_ getstartedlab_web.2   diguage/01-get-started:part2   myvm2               Shutdown            Shutdown 26 minutes ago
    tl396s3vp7pr         \_ getstartedlab_web.2   diguage/01-get-started:part2   myvm2               Shutdown            Shutdown 28 minutes ago
    conj00k1q32t         \_ getstartedlab_web.2   diguage/01-get-started:part2   myvm2               Shutdown            Shutdown 30 minutes ago
    exg8je3dt558        getstartedlab_web.3       diguage/01-get-started:part2   myvm1               Running             Running 26 minutes ago
    tqqrhqm93fs6         \_ getstartedlab_web.3   diguage/01-get-started:part2   myvm1               Shutdown            Shutdown 26 minutes ago
    oynsvvfhznxq         \_ getstartedlab_web.3   diguage/01-get-started:part2   myvm1               Shutdown            Shutdown 28 minutes ago
    zg7togioehbp         \_ getstartedlab_web.3   diguage/01-get-started:part2   myvm1               Shutdown            Shutdown 30 minutes ago
    seej60hjmndw        getstartedlab_web.4       diguage/01-get-started:part2   myvm2               Running             Running 26 minutes ago
    etj0r1xo2cv8         \_ getstartedlab_web.4   diguage/01-get-started:part2   myvm2               Shutdown            Shutdown 26 minutes ago
    ozxn96kokvd1         \_ getstartedlab_web.4   diguage/01-get-started:part2   myvm2               Shutdown            Shutdown 28 minutes ago
    yrpxcuhxt3bo        getstartedlab_web.5       diguage/01-get-started:part2   myvm1               Running             Running 27 minutes ago
    1 这个服务测试过扩缩容,所以多了一些关闭状态。
  8. 通过 docker service ls 来查看服务状态

    $ docker service ls
    ID                  NAME                MODE                REPLICAS            IMAGE                          PORTS
    mb300tn4cqp2        getstartedlab_web   replicated          5/5                 diguage/01-get-started:part2   *:4000->80/tcp (1)
    1 注意这里的 REPLICAS 项。正常状态下,分子分母一样。如果出现 0/5 这表示服务状态异常。
  9. 可以通过 docker-machine ssh myvm1 进去到 machine 去查看 container 的状态。

    $ docker-machine ssh myvm1
       ( '>')
      /) TC (\   Core is distributed with ABSOLUTELY NO WARRANTY.
     (/-_--_-\)           www.tinycorelinux.net
    
    docker@myvm1:~$ (1)
    1 以下命令请注意每个命令行开头的用户名和所在机器。
  10. 通过 docker container ls 查看 container 的状态

    docker@myvm1:~$ docker container ls
    CONTAINER ID        IMAGE                          COMMAND             CREATED             STATUS              PORTS               NAMES
    516d1ccb23c7        diguage/01-get-started:part2   "python app.py"     32 minutes ago      Up 32 minutes       80/tcp              getstartedlab_web.3.exg8je3dt5586l7hgt8xvafuz (1)
    39a0f3cd0e77        diguage/01-get-started:part2   "python app.py"     33 minutes ago      Up 33 minutes       80/tcp              getstartedlab_web.5.yrpxcuhxt3bojd2h9i41mjjci
    337a364ef099        diguage/01-get-started:part2   "python app.py"     33 minutes ago      Up 33 minutes       80/tcp              getstartedlab_web.1.ndbmgp8wlvp0ru88e4lwj5art
    1 异常情况下,可能没有 container 信息。
  11. 通过 docker images 查看镜像状态

    docker@myvm1:~$ docker images
    REPOSITORY               TAG                 IMAGE ID            CREATED             SIZE
    diguage/01-get-started   <none>              13e8d6379f20        38 hours ago        153MB (1)
    1 异常情况下,可能没有镜像信息

Stacks

  1. stack — A stack is a group of interrelated services that share dependencies, and can be orchestrated and scaled together.

# 修改 docker-compose.yml 增加服务定义,然后发布
docker stack deploy -c docker-compose.yml getstartedlab

# 查看服务状态
docker stack services getstartedlab

# 查看服务中的容器状态
docker stack ps getstartedlab

# 部署 Redis 之前,需要在 manager 节点创建相关目录
docker-machine ssh myvm1 "mkdir ./data"

# 关闭服务
docker stack rm getstartedlab

查看 Web 页面,确认服务状态

version: "3"
services:
  web:
    image: diguage/01-get-started:part2
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

增加 Redis 服务

# 部署 Redis 之前,需要在 manager 节点创建相关目录
docker-machine ssh myvm1 "mkdir ./data" (1)
1 通过这里也可以看出,是在 myvm1 内部启动了 Docker container。
version: "3"
services:
  web:
    image: diguage/01-get-started:part2
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - "/home/docker/data:/data"
    deploy:
      placement:
        constraints: [node.role == manager]
    command: redis-server --appendonly yes
    networks:
      - webnet
networks:
  webnet:

Question

  1. Web 服务是如何做到 Redis 服务的?根据服务名称吗?

    ??

  2. 负载均衡是如何做的?能否配置不同的负载均衡算法?

    ??

支付宝

微信

感谢您的支持,😜