(一)Docker 的 “Hello World”

281 阅读8分钟

简介

之前就了解过Docker最简单但是不准确的理解是:轻量级的虚拟机

不得不说虚拟化这一话题始终贯穿,从分时操作系统RAID,从虚拟机云原生都有它的思想

三个概念

  1. 镜像(Image):类似于虚拟机中的镜像,是一个包含有文件系统的面向Docker引擎的只读模板。任何应用程序运行都需要环境,而镜像就是用来提供这种运行环境的。
  2. 容器(Container):容器是镜像创建的应用实例,可以创建、启动、停止、删除容器,各个容器之间是是相互隔离的,互不影响。注意:镜像本身是只读的,容器从镜像启动时,Docker在镜像的上层创建一个可写层,镜像本身不变。
  3. 仓库(Repository):类似于代码仓库,这里是镜像仓库,是Docker用来集中存放镜像文件的地方。注意与注册服务器(Registry)的区别:注册服务器是存放仓库的地方,一般会有多个仓库;而仓库是存放镜像的地方,一般每个仓库存放一类镜像,每个镜像利用tag进行区分,比如Ubuntu仓库存放有多个版本(12.04、14.04等)的Ubuntu镜像。

Hello World

  1. 打开terminal,输入docker version,查看安装是否成功

    Client:
     Cloud integration: v1.0.20
     Version:           20.10.10
     API version:       1.41
     Go version:        go1.16.9
     Git commit:        b485636
     Built:             Mon Oct 25 07:43:15 2021
     OS/Arch:           darwin/amd64
     Context:           default
     Experimental:      true
    
    Server: Docker Engine - Community
     Engine:
      Version:          20.10.10
      API version:      1.41 (minimum version 1.12)
      Go version:       go1.16.9
      Git commit:       e2f740d
      Built:            Mon Oct 25 07:41:30 2021
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          1.4.11
      GitCommit:        5b46e404f6b9f661a205e28d59c982d3634148f8
     runc:
      Version:          1.0.2
      GitCommit:        v1.0.2-0-g52b36a2
     docker-init:
      Version:          0.19.0
      GitCommit:        de40ad0
    
  2. docker run hello-world

➜  ~ docker run hello-world
​
Hello from Docker!
This message shows that your installation appears to be working correctly.
​
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
​
To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash
​
Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/
​
For more examples and ideas, visit:
 https://docs.docker.com/get-started/
​

docker run命令根据image启动container

Docker首先检查本地是否拥有该image,没有的话从Repository下载,然后运行

由于之前我运行过docker pull hello-world,所以这里没有下载过程

ubuntu

docker run -it ubuntu bash

➜  ~ docker run -it ubuntu bash
root@4601014882cf:/# pwd
/
root@4601014882cf:/# ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@4601014882cf:/#

参数说明:

  • -i: 交互式操作。
  • -t: 终端。
  • ubuntu: ubuntu 镜像。
  • /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

要退出终端,直接输入 exit:

其他命令

拉取docker镜像

docker pull image_name

查看宿主机上的镜像,Docker镜像保存在/var/lib/docker目录下:

docker images

删除镜像

docker rmi  image_name   

查看当前有哪些容器正在运行,下述两个命令等价

docker ps
docker container ls

查看所有容器

docker ps -a

启动、停止、重启容器命令:

docker start container_name/container_id
docker stop container_name/container_id
docker restart container_name/container_id

后台启动一个容器后,如果想进入到这个容器,可以使用attach命令:

docker attach container_name/container_id

删除容器的命令:

docker rm container_name/container_id

查看当前系统Docker信息

docker info

从Docker hub上下载某个镜像:

docker pull centos:latest

docker run的参数:

-d       分离终端
-P       随机地把容器中所有暴露的端口映射到本地端口
--name   指定容器名字
--rm     本次运行完就自动删除此容器

Terminology

  • Images - The blueprints of our application which form the basis of containers.

  • Containers - Created from Docker images and run the actual application.

  • Docker Daemon - The background service running on the host that manages building, running and distributing Docker containers. The daemon is the process that runs in the operating system which clients talk to.

  • Docker Client - The command line tool that allows the user to interact with the daemon.

  • Docker Hub - A registry of Docker images. You can think of the registry as a directory of all available Docker images.

创建自己的image

概念

  • 分类1
    • base image:image that have no parent image
    • child image:基于base image增加了功能
  • 分类2
    • official image:officially maintained and supported by the folks at Docker. one word long.
    • user image:created and shared by users. user/image-name.

Dockerfile

Dockerfile告诉Docker在创建image的时候该怎么做,是文本文件

提交操作

docker push username/image_name

image.png

部署到AWS

待完成😇😇

MULTI-CONTAINER ENVIRONMENTS

把每个服务的沙盒分开是明智的

这是Docker在微服务时代🔥的原因

Docker网络

docker network ls 查看当前的网络

NETWORK ID     NAME      DRIVER    SCOPE
1d6b5782ac77   bridge    bridge    local
be2f04acafd5   host      host      local
17b1da316665   none      null      local

docker network inspect bridge 仔细审视某个网络

[
    {
        "Name": "bridge",
        "Id": "1d6b5782ac776413ca219307ba709776bab08e0b7d0043dd21dad2fd1fe2bd8d",
        "Created": "2021-11-24T01:43:19.15368684Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "658636b7a5898f5323aaae3cbd04b7855a8c9bfb24bdc71c1d0216ad935e59aa": {
                "Name": "es",
                "EndpointID": "a8dbadeeb5bf480c65b5337f9926ff9503f8230e4a124060dd054a841ae790f7",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            },
            "f37cb6348fac669786a4d333f5ca6faac54fef1da5c74518c76647755b54f15f": {
                "Name": "funny_hoover",
                "EndpointID": "9362e7fc00222c67e7dccdb1929bf215a7cc00e405dde868887d9c4f5c4d3ec6",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "tspz77nox8bd1m7labzjclgdm": {
                "Name": "tspz77nox8bd1m7labzjclgdm",
                "EndpointID": "b859aed856aad0622d211756138656aa9d64cab260c048eb00bb8aafbe939856",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

我看看到有很多containerbridge上工作,container创建时默认在bridge

一些命令

  • 新建网络

docker network create foodtrucks-net

  • 指定容器运行在哪个网络上

docker run --net foodtrucks-net

automatic service discovery

containers can not only communicate by IP address, but can also resolve a container name to an IP address

example

docker-curriculum.com/

foodtrucks-web 需要从ES 处获得HTTP response

➜  ~ docker run -P --rm zhenglinli/foodtrucks-web
/usr/local/lib/python3.6/dist-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (3.0.4) doesn't match a supported version!
  RequestsDependencyWarning)
Unable to connect to ES. Retrying in 5 secs...
Unable to connect to ES. Retrying in 5 secs...
Unable to connect to ES. Retrying in 5 secs...
Out of retries. Bailing out...

目前是连接不上的,因为不在同一个网络下

目前,EShttp://localhost:9200/上运行,可以通过本机访问但是不能在容器里访问

image.png

在容器中,我们通过docker network inspect bridge来查看运行在bridge网络上的情况

➜  ~ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "1d6b5782ac776413ca219307ba709776bab08e0b7d0043dd21dad2fd1fe2bd8d",
        "Created": "2021-11-24T01:43:19.15368684Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "658636b7a5898f5323aaae3cbd04b7855a8c9bfb24bdc71c1d0216ad935e59aa": {
                "Name": "es",
                "EndpointID": "a8dbadeeb5bf480c65b5337f9926ff9503f8230e4a124060dd054a841ae790f7",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

我们看到,容器中我们可以通过172.17.0.3:9200来访问ES

➜  ~ docker run -it --rm zhenglinli/foodtrucks-web bash
root@227190b18e94:/opt/flask-app# curl 172.17.0.2:9200
curl: (7) Failed to connect to 172.17.0.2 port 9200: Connection refused
root@227190b18e94:/opt/flask-app# curl 172.17.0.3:9200
{
  "name" : "oyVim2N",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "rBB5jgUIRMSnb4PHPCD3Xw",
  "version" : {
    "number" : "6.3.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "053779d",
    "build_date" : "2018-07-20T05:20:23.451332Z",
    "build_snapshot" : false,
    "lucene_version" : "7.3.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

两个问题:

  • 不同container间怎么通信?

  • 怎么确保隔离?

  1. 我们创建自己的网络foodtrucks-net,用于esfoodtrucks-web 的 通信:

docker network create foodtrucks-net

  1. 在网络foodtrucks-net上,启动es

docker run -d --name es --net foodtrucks-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.3.2

查看网络上的情况:

docker network inspect foodtrucks-net

➜  ~ docker network inspect foodtrucks-net
[
    {
        "Name": "foodtrucks-net",
        "Id": "9deb3da791fd3d709c99f4152fb055e9f5744dc83adf1c692b732ff3f98c942f",
        "Created": "2021-11-24T04:11:13.5456846Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "7231ee0b0e2feb1084cb136cc2aa2b1fef7d5a0b076b6d76a72a5c759a7af7ae": {
                "Name": "es",
                "EndpointID": "ada4f19a762b810c8949d5f2286dc7db63139582f7af84f0ec28ab67835af38f",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

es container is now running inside the foodtrucks-net bridge network

  1. 启动foodtrucks-web

docker run -d --net foodtrucks-net -p 5000:5000 --name foodtrucks-web zhenglinli/foodtrucks-web

Kubernetes

it can make dealing with multi-container apps easier.