容器镜像:https://hub.docker.com/
Docker架构图: https://ruby-china.org/topics/22004
Docker使用客户端-服务器(client-server)架构模式。Docker客户端会与Docker守护进程进行通信。Docker守护进程会处理复杂繁重的任务,例如建立、运行、发布你的Docker容器。
Docker客户端和守护进程可以运行在同一个系统上,当然你也可以使用Docker客户端去连接一个远程的Docker守护进程。Docker客户端和守护进程之间通过socket或者RESTful API进行通信。
Docker_host端运行一个子程序:Docker_daemon即守护进程,所以运行docker_daemon的进程的服务器就是守护进程服务器。docker_daemon可以监听在套接字上,为了安全,docker_daemon默认只提供本机的unix socket文件的套接字,支持三种类型的套接字:ipv4+端口、ipv6+端口、UNIX Socket file(本地文件),docker_daemon只监听了第三种套接字即本地文件,像mysql只监听了127.0.0.1,所以docker_daemon只允许客户端是本地的。
镜像是分层构建的,需要把镜像下载到本地用以共享,镜像需要在docker主机的本地存储。
由于所有镜像都是只读的,所以启动容器时都是基于镜像来启动,在已有镜像的基础上,为容器创建一个专用的可写层,从而来启动一个容器。
Docker有两个主要的部件:
Docker: 开源的容器虚拟化平台。
Docker Hub: 用于分享、管理Docker容器的Docker SaaS平台。
Docker守护进程
如上图所示,Docker守护进程运行在一台主机上。用户并不直接和守护进程进行交互,而是通过Docker客户端间接和其通信。
Docker客户端
Docker客户端,实际上是
docker
的二进制程序,是主要的用户与Docker交互方式。它接收用户指令并且与背后的Docker守护进程通信,如此来回往复。
Docker的内部
要理解Docker的内部构建,必须知道以下三种部件:
- Docker镜像 (Docker images)
- Docker仓库 (Docker registeries)
- Docker容器(Docker containers)
Docker镜像
Docker镜像是一个只读的模板。举个例子,一个镜像可以包含一个运行在Apache上的Web应用和其使用的Ubuntu操作系统。
镜像是用来创建容器的。Docker提供了简单的来建立新的镜像或者升级现有的镜像,你也可以下载别人已经创建好的镜像。Docker镜像是Docker的构造部分。
镜像是分层构建的,需要把镜像下载到本地用以共享,镜像需要在docker主机的本地存储。
由于所有镜像都是只读的,所以启动容器时都是基于镜像来启动,在已有镜像的基础上,为容器创建一个专用的可写层,从而来启动一个容器。
Docker仓库
Docker仓库用来保存镜像。可以理解为代码控制中的代码仓库。同样的,Docker仓库也有公有和私有的概念。
公有的Docker仓库名字是Docker Hub。Docker Hub提供了庞大的镜像集合供使用。这些镜像可以是你自己创建的,或者你也可以在别人的镜像基础上创建。Docker仓库是Docker的分发部分。
Docker对象 https://docs.docker.com/engine/docker-overview/
使用Docker时,可以创建和使用图像,容器,网络,卷,插件和其他对象。可以对对象进行增、删、改、查。
Docker容器
Docker容器和文件夹很类似。一个Docker容器包含了所有的某个应用运行所需要的环境。每一个Docker容器都是从Docker镜像创建的。
Docker容器可以运行、开始、停止、移动和删除。每一个Docker容器都是独立和安全的应用平台。Docker容器是Docker的运行部分。
Docker Registry http://dockone.io/article/104
1、提供镜像存储的仓库
2、提供用户获取镜像时的认证功能
3、提供当前服务器提供的所有服务器的搜索索引
Docker Registry有很多仓库,一个仓库有一个名称,一个仓库只存放一个应用程序的镜像。比如nginx程序,但是nginx会有不同的版本,所以nginx的不同版本都存放在同一个仓库中,这个仓库名称就是应用程序名称:nginx。
nginx仓库中会存放nginx不同版本:nginx1.10、nginx1.12等,如何标记不同版本的镜像呢?是通过为每一个镜像额外添加一个组件:标签。
所以用 仓库名 + 标签 才能唯一标识一个镜像。如果访问镜像时只给了仓库名,而没有标签,默认是最新标签。
对于程序而言,奇数是开发板,而偶数是稳定版。
Docker容器是如何工作的
一个Docker容器包含了一个操作系统、用户添加的文件和元数据(meta-data)。我们可以看到,每个容器都是从镜像建立的。镜像告诉Docker容器内包含了什么,当容器启动时运行什么程序,还有许多配置数据。Docker镜像是只读的。当Docker运行一个从镜像建立的容器,它会在镜像顶部添加一个可读写的层,应用程序可以在这里运行。
当你运行docker容器时发生了什么
不论你使用docker
命令或者是RESTful API,Docker客户端都会告诉Docker守护进程运行一个容器。
$ sudo docker run -i -t ubuntu /bin/bash
让我们来分析这个命令。Docker客户端使用docker
命令来运行,run
参数表明客户端要运行一个新的容器。Docker客户端要运行一个容器需要告诉Docker守护进程的最小参数信息是:
- 这个容器从哪个镜像创建,这里是
ubuntu
,基础的Ubuntu镜像。 - 在容器中要运行的命令,这里是
/bin/bash
,在容器中运行Bash shell。
那么运行这个命令之后在底层发生了什么?
按照顺序,Docker做了这些事情:
- 拉取
ubuntu
镜像: Docker检查ubuntu
镜像是否存在,如果在本地没有该镜像,Docker会从Docker Hub下载。如果镜像已经存在,Docker会使用它来创建新的容器。 - 创建新的容器: 当Docker有了这个镜像之后,Docker会用它来创建一个新的容器。
- 分配文件系统并且挂载一个可读写的层: 容器会在这个文件系统中创建,并且一个可读写的层被添加到镜像中。
- 分配网络/桥接接口: 创建一个允许容器与本地主机通信的网络接口。
- 设置一个IP地址: 从池中寻找一个可用的IP地址并且添加到容器上。
- 运行你指定的程序: 运行指定的程序。
- 捕获并且提供应用输出: 连接并且记录标准输出、输入和错误让你可以看到你的程序是如何运行的。
你现在拥有了一个运行着的容器!从这里开始你可以管理你的容器,与应用交互,应用完成之后,可以停止或者删除你的容器。
安装及使用docker
镜像:https://mirrors.tuna.tsinghua.edu.cn/
docker软件包 https://mirrors.tuna.tsinghua.edu.cn/centos/7/extras/x86_64/Packages/ 但是版本比较老
清华大学的docker的repo文件:https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/
此版本比较新:https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/7/x86_64/stable/Packages/
# cd /etc/yum.repos.d/
# wget https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo 下载repo文件
# vim docker-ce.repo //由于此文件中指向的docker版本比较老,所以对此文件进行修改
:%a@https://download.docker.com/@https://mirrors.tuna.tsinghua.edu.cn/docker-ce/@
yum.repos.d]# yum repolist
# yum install docker-ce //如果用老版本的话就是yum install docker
docker程序环境:
环境配置文件:
/etc/sysconfig/docker-network
/etc/sysconfig/docker-storage
/etc/sysconfig/docker
Unit File:
/usr/lib/systemd/system/docker.service
Docker Registry 配置文件:
/etc/containers/registries.conf
docker-ce:
配置文件:/etc/docker/daemon.json //这个文件默认是不存在的,需要自己创建
Docker镜像加速:为了下载镜像速度较快,需要定义一个镜像加速器
Docker 中国官方镜像加速 https://www.docker-cn.com/registry-mirror 较慢
阿里云加速器
把下面这段话加进到/etc/docker/daemon.json文件中去
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}//上述是json函数的数组,key是registry-mirrors,值是https://registry.docker-cn.com,值可以有多个,用","隔开
# mkdir /etc/docker
# vim /etc/docker/daemon.json //添加此段话
{
"registry-mirrors": ["https://registry.docker-cn.com"]
}
# systemctl start docker.service
# docker version //查看docker版本
Client:
Version: 18.09.2
API version: 1.39
Go version: go1.10.6
Git commit: 6247962
Built: Sun Feb 10 04:13:27 2019
OS/Arch: linux/amd64
Experimental: falseServer: Docker Engine - Community
Engine:
Version: 18.09.2
API version: 1.39 (minimum version 1.12)
Go version: go1.10.6
Git commit: 6247962
Built: Sun Feb 10 03:47:25 2019
OS/Arch: linux/amd64
Experimental: false
# docker info //查看更为详细的docker信息
Containers: 0 Running: 0 Paused: 0 Stopped: 0 Images: 0 Server Version: 18.09.2 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true Logging Driver: json-file Cgroup Driver: cgroupfs Plugins: Volume: local Network: bridge host macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog Swarm: inactive Runtimes: runc Default Runtime: runc Init Binary: docker-init containerd version: 9754871865f7fe2f4e74d43e2fc7ccd237edcbce runc version: 09c8266bf2fcf9519a651b04ae54c967b9ab86ec init version: fec3683 Security Options: seccomp Profile: default Kernel Version: 3.10.0-957.el7.x86_64 Operating System: CentOS Linux 7 (Core) OSType: linux Architecture: x86_64 CPUs: 6 Total Memory: 3.692GiB Name: node1 ID: LFHI:LTRE:6TA4:CJHP:HHPO:AAIH:I54H:NMPR:CJ4I:SKAI:CAQV:7GRP Docker Root Dir: /var/lib/docker Debug Mode (client): false Debug Mode (server): false Registry: https://index.docker.io/v1/ Labels: Experimental: false Insecure Registries: 127.0.0.0/8 Registry Mirrors: https://registry.docker-cn.com/ Live Restore Enabled: false Product License: Community Engine
# docker //可以查看docker的子命令
# docker container --help //现在单独管理
Docker命令: http://dockone.io/article/102 http://www.runoob.com/docker/docker-command-manual.html
Alpine简介 https://yeasy.gitbooks.io/docker_practice/cases/os/alpine.html
下载镜像
# docker image pull nginx:1.14-alpine //下载nginx的alpine镜像
# docker image ls //显示镜像
# docker pull busybox
# docker image ls --help
启动容器
# docker container --help //容器命令
# docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
容器ID 基于哪个镜像启动的容器 在容器中运行的命令 容器映射的端口
COMMAND:容器中运行的命令,docker容器是为了运行单个程序的,当基于一个镜像启动一个程序的时候运行哪个程序呢?每个镜像都有定义默认运行的程序。但是也可以修改默认程序。
# docker run --help http://www.runoob.com/docker/docker-run-command.html
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# docker network ls
NETWORK ID NAME DRIVER SCOPE 5ebae7e509fa bridge bridge local 如果不指定,则默认此 b255b50dc21e host host local db26f5263d07 none null local
Docker network
https://www.ibm.com/developerworks/cn/linux/l-docker-network/index.html
https://docs.docker.com/network/
启动的容器会自动拥有inet 172.17.0.1网络中的地址,并且是nat桥,即可以进行地址转换,通过inet 192.168.128.131与外界通信,可以请求出去,但无法进来。
# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.128.131 netmask 255.255.255.0 broadcast 192.168.128.255 inet6 fe80::f528:9792:1744:13a7 prefixlen 64 scopeid 0x20<link> ether 00:0c:29:ee:53:1e txqueuelen 1000 (Ethernet) RX packets 109521 bytes 75247038 (71.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 161663 bytes 335973137 (320.4 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Docker run 命令
OPTIONS说明:
-a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
-d: 后台运行容器,并返回容器ID;
-i: 以交互模式运行容器,通常与 -t 同时使用;
-p: 端口映射,格式为:主机(宿主)端口:容器端口
-t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
--name="nginx-lb": 为容器指定一个名称;
--dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
-h "mars": 指定容器的hostname;
-e username="ritchie": 设置环境变量;
--env-file=[]: 从指定文件读入环境变量;
--cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
-m :设置容器使用内存最大值;
--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container:<name|id> 四种类型;
--link=[]: 添加链接到另一个容器;
--expose=[]: 开放一个端口或一组端口;
实例
使用docker镜像nginx:latest以后台模式启动一个容器,并将容器命名为mynginx。
docker run --name mynginx -d nginx:latest
使用镜像nginx:latest以后台模式启动一个容器,并将容器的80端口映射到主机随机端口。
docker run -P -d nginx:latest
使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,主机的目录 /data 映射到容器的 /data。
docker run -p 80:80 -v /data:/data -d nginx:latest
绑定容器的 8080 端口,并将其映射到本地主机 127.0.0.1 的 80 端口上。
$ docker run -p 127.0.0.1:80:8080/tcp ubuntu bash
使用镜像nginx:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
runoob@runoob:~$ docker run -it nginx:latest /bin/bash root@b8573233d675:/#
/ # exit //退出容器,再次查看时,此容器处于停滞状态
# docker container start -ai busybox //启动之前创建的容器
# docker rm busybox //容器停止之后可以删除
# docker ps -a //再次查看时就没有此容器了
创建nginx容器
# docker run --name web1 -d nginx:1.14-alpine //即使本地没有镜像也无所谓,会自动下载镜像到本地的
# docker ps //nginx容器已经启动了 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3ecb4f5d9a10 nginx:1.14-alpine "nginx -g 'daemon of?? 2 minutes ago Up 2 minutes 80/tcp web1
nginx -g 'daemon of?? //这里创建nginx容器时,是将程序跑在后台的,所以会出现这种问题。在容器中运行任何程序都不要运行在后台,
因为一个容器就是为了运行一个程序,如果这个程序还要在后台运行,那么这个容器就没有程序运行了,
那么没有程序运行容器就会结束,它是唯一进程,是支撑容器的骨架# docker inspect web1 //查看容器web1的相关信息
{ "Id": "3ecb4f5d9a109c5714718c81acf592890c9cd6bcee95d0f1e50b103689af1bc0", "Created": "2019-02-15T08:45:44.059155956Z", "Path": "nginx", "Args": [ "-g", "daemon off;" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 35189, "ExitCode": 0, "Error": "", "StartedAt": "2019-02-15T08:45:44.947856586Z", "FinishedAt": "0001-01-01T00:00:00Z" }, 。。。
"Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "5ebae7e509fa740a57623ec16baa50026135b09c7c98485cbe9784a272e7bdda", "EndpointID": "2bd43ccab59dee023a35dd28cfdc1238dc9e0ee032b5c42daca6f5bf2351ec90", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } }# curl 172.17.0.2 //访问nginx的web页面
# docker run --name kvstor1 -d redis:4-alpine
Unable to find image 'redis:4-alpine' locally //本地没有此镜象,就下载 4-alpine: Pulling from library/redis 6c40cc604d8e: Already exists e42672a2ca6a: Pull complete 823e4275fef6: Pull complete 0c49a8a142d3: Pull complete 62c3ab7a67af: Pull complete d8e4fee2dbc2: Pull complete Digest: sha256:99c3c1e02e5e794d7309003d4f5d045cba0b94911b9b3a2659bb15e8f4261954 Status: Downloaded newer image for redis:4-alpine da481ee71e4581928a9c56b975561ddc4f0c8d7e4b627fcb087acf99e60336f5# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES da481ee71e45 redis:4-alpine "docker-entrypoint.s?? About a minute ago Up About a minute 6379/tcp kvstor1 //正在运行 3ecb4f5d9a10 nginx:1.14-alpine "nginx -g 'daemon of?? 35 minutes ago Up 34 minutes 80/tcp web1# docker container exec --help //访问redis容器,需要有redis客户端,此镜象自带客户端,所以可以绕过容器的边界登陆进去。
Usage: docker container exec [OPTIONS] CONTAINER COMMAND [ARG...]
# docker exec -it kvstor1 /bin/sh //
/data # ps PID USER TIME COMMAND 1 redis 0:01 redis-server 12 root 0:00 /bin/sh 17 root 0:00 ps /data # netstat -tunlp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN - tcp 0 0 :::6379 :::* LISTEN - /data # exit关于容器的日志,由于一个容器只运行了单个程序,所以就直接把日志发送到了控制台上了,而不是保存在文件中
# docker logs web1 //查看web1容器的日志
172.17.0.1 - - [15/Feb/2019:09:10:42 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.29.0" "-"
Docker容器状态的转换和相关常用命令