Docker 学习笔记:第2节 Docker使用入门

Posted Frank201608

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker 学习笔记:第2节 Docker使用入门相关的知识,希望对你有一定的参考价值。

 

  • 运行一个新的容器:
docker run -ti --name second ubuntu:16.04 bash

命令解释:

  • Docker run 是从一个镜像运行一个容器的指令。
  • -ti 参数的含义是:terminal interactive,这个参数可以让我们进入容器的交互式终端。
  • --name 指定容器的名字,后面的 first 就是我们给这个容器起的名字。
  • ubuntu:16.04 是致命从哪个镜像运行容器,ubuntu是仓库名,16.04是标签。
  • bash 指明我们使用 bash 终端。

镜像是一个静态的概念。

运行完以上命令,发现我们已经进入了容器:

退出我们在上一步运行的容器:直接输入 exit,然后回车就可以退出。这其实是终止了我们的容器:

  • 查看当前的容器:
docker ps -a
  • 提交为一个新的镜像

以把刚才名为 first 的容器提交为一个新的镜像:

docker commit [容器名称] my_image:v1.0 

从这个新的镜像创建容器:

root@hongkong-web1:~# docker run -ti --name my_container3 my_image:v1.0 bash
root@09213c43add4:/# 

正使用 Docker 开发的时候需要避免这种从容器提交镜像的方法!

 

如果使用“-d”参数的话,容器启动后会返回容器 ID

这里说的后台运行容器长久运行不是一回事,后台运行只是说不会在宿主主机的终端打印输出,但是你给定的指令执行完成后,容器就会自动退出,所以,长久运行与否是与你给定的需要容器运行的命令有关,与“-d”参数没有关系。

 

  • 进入容器和终止容器

进入容器一般有三种方法:

  • ssh 登录
  • attach 和 exec
  • nesenter

docker exec -ti   [你的容器名称] bash

docker attach  [你的容器名称] 

Docker run 指令会给容器分配一个进程,一个容器一个进程!

所以 attach 实际就是进入容器的主进程,所以无论你同时 attach 多少,其实都是进入了主进程。

比如下图,我使用两次 attach 进入同一个容器,然后在一个 attach 里面运行的指令也会在另一个 attach 里面同步输出,因为它们两个 attach 进入的根本就是一个进程!

在 exec 里面执行 exit 命令,你只是关掉了 exec 命令新开的进程,而主进程依旧在运行,所以容器并不会停止

而在 attach 里面运行 exit 命令,你实际是终止了主进程,所以容器也就随之被停止了

总结一下,attach 的使用不会在容器开辟新的进程;exec 主要用在需要给容器开辟新进程的情况下。

 

  • 删除容器
docker rm nameOfContainer

如何终止一个运行的容器:

容器在后台运行,这个容器已经完成了任务,可以把它终止了,一种办法是 attach 进入容器之后运行“exit”结束容器主进程,这样容器也就随之被终止了。另一种比较推荐的方法是运行:kill nameOfContainer

  • Docker 日志
docker logs logtest
  • 限制容器资源

执行“Docker run”命令时可以使用的和内存限制有关的参数如下:

参数简介
-m, - -memory内存限制,格式:数字+单位,单位可以是 b、k、m、g,最小 4M
-- -memory-swap内存和交换空间总大小限制,注意:必须比 -m 参数大

Docker run 命令执行的时候可以使用的限制 CPU 的参数如下:

参数简介
-- -cpuset-cpus=""允许使用的 CPU 集
-c,- -cpu-shares=0CPU 共享权值
-- -cpu-quota=0限制 CPU CFS 配额,必须不小于 1ms,即 >=1000
cpu-period=0限制 CPU CFS 调度周期,范围是 100ms~1s,即 [1000,1000000]
  

1、可以设置在哪些 CPU 核上运行,比如下面的指令指定容器进程可以在 CPU1 和 CPU3 上运行:

sudo docker run -ti --cpuset-cpus="1,3" --name cpuset ubuntu:16.04 bash

  • 查看容器详细信息
docker inspect [nameOfContainer]
  • 查看容器最近一个进程
docker top [nameOfContainer]
  • 停止一个正在运行的容器
docker stop [nameOfContainer]
  • 继续运行一个被停止的容器
docker restart [nameOfContainer]
  • 暂停一个容器进程
     docker pause [nameOfContainer]
  • 取消暂停
 docker unpause [nameOfContainer]
  • 终止一个容器
sudo docker kill [nameOfContainer]
  • 容器的生命周期

 

  1. 因为容器应该只是一个进程,数据需要使用数据卷保存

  2. 尽量坚持“一个容器,一个进程”的使用理念,当然,在调试阶段,可以使用exec命令为容器开启新进程

 

更多关于镜像的操作

  • 删除镜像
sudo docker rmi [nameOfImage]
  • 查看镜像操作记录
sudo docker history [nameOfImage]
  • 给镜像设置一个新的仓库:版本对
sudo docker tag my_image:v1.0 my:v0.1

  运行了上面的指令我们就得到了一个新的,和原来的镜像一模一样的镜像。

  • 查看镜像详细信息
sudo docker inspect [nameOfImage]

Docker 数据管理

  • 创建一个数据卷

在运行 Docker run 命令的时候使用 -v 参数为容器挂载一个数据卷:

sudo docker run -ti --name volume1 -v /myDir ubuntu:16.04 bash
  • 删除一个数据卷
docker rm -v volume1 

数据卷是用来持久化数据的,所以数据卷的生命周期独立于容器。所以在容器结束后数据卷并不会被删除,如果你希望删除数据卷,可以在使用 docker rm 命令删除容器的时候加上 -v 参数。如果你删除挂载某个数据卷的所有容器的同时没有使用 -v 参数清理这些容器挂载的数据卷,你之后再想清理这些数据卷会很麻烦,所以在你确定某个数据卷没有必要存在的时候,在删除最后一个挂载这个数据卷的容器的时候,使用 -v 参数删除这个数据卷。

 

  • 挂载一个主机目录作为数据卷
docker run -ti --name volume2 -v /home/zsc/Music/:/myShare ubuntu:16.04 bash

把宿主主机的目录 /home/zsc/Music 挂载到容器的 myShare 目录下,容器内的 myShare 目录就会包含宿主主机对应目录下的文件。Docker 挂载数据卷的默认权限是读写,可以通过 :ro 指令为只读

 docker run -ti --name volume2 -v /home/zsc/Music/:/myShare:ro ubuntu:16.04 bash

数据卷容器(Data Volume Container)

所谓数据卷容器,其实就是一个普通的容器,只不过这个容器专门作为数据卷供其它容器挂载

首先,在运行 docker run 指令的时候使用 -v 参数创建一个数据卷容器(这和我们之前创建数据卷的指令是一样的):

sudo docker run -ti  -d -v /dataVolume --name v0 ubuntu:16.04

然后,创建一个新的容器挂载刚才创建的数据卷容器中的数据卷:使用 --volumes-from 参数

 sudo docker run -ti --volumes-from v0 --name v1 ubuntu:16.04 bash

然后,我们的新容器里就可以看到数据卷容器的数据卷内容。

注意:

1、数据卷容器被挂载的时候不必保持运行!

2、如果删除了容器 v0 和 v1,数据卷并不会被删除。如果想要删除数据卷,应该像本文1.1小节介绍的那样在执行 docker rm 命令的时候使用 -v 参数。


Docker 网络

首先从之前的 Ubuntu:16.04 创建一个容器:

sudo docker run -ti --name Exercise ubuntu:16.04 bash

进入之后依次执行下述命令:

apt-get update
apt-get install vim
apt-get install net-tools
apt install iputils-ping 
apt install apache2
apt install apache2-utils
apt install openssh-server
apt install openssh-client

之后使用 vim 修改:

vim /etc/ssh/sshd_config

把“PermitRootLogin”的内容改为 yes,保存。

输入:

passwd

输入你的 root 密码。(密码需要记好哦!

完成之后退出容器。使用 docker ps -a 找到你刚才运行的容器,找到之后从这个容器提交新镜像:

zsc@Berry:~$ sudo docker commit -m "My network exercise" Exercise net:v1.0

说明:

-m 是添加一个对镜像的简短说明,和 git 类似;

其后一个参数是刚刚容器的名字或者 ID;

最后是新镜像的名字:标签对。

后面将使用这个 net:v1.0 镜像运行容器!

 

端口暴露

我们可以使用 -p 参数执行端口映射,格式如下:

-p hostPort:containerPort 映射所有 IP 地址上的指定端口到容器内部

-p ip:hostPort:containerPort 映射指定 IP 地址上的指定端口到容器内部

-p ip::containerPort 映射指定 IP 地址上的任意端口到容器内部

现在,我们来举个例子看看端口映射到底是什么:

sudo docker run -ti --name web -p 80:80 net:v1.0 bash

这条命令启动了一个容器,映射宿主主机所有 IP 的80端口到容器的80端口。

然后,在容器里面启动 Apache 服务(之前的准备工作中,我们已经安装好了 ApacheWeb 服务器,它提供了一个默认网页),容器里面运行如下指令:

apache2ctl start

然后查看容器的 IP 地址是“172.17.0.2”(你的 IP 可能有所不同)。此时,打开你的宿主主机(即安装 Docker 的计算机)上的浏览器,输入http://172.17.0.2 就可以访问 Apache 服务器的默认主页了。然后,使用 ifconfig 命令查看宿主主机的 IP 地址,发现通过 http://宿主主机的 IP ,可以访问 Apache 服务器主页。

端口暴露不仅仅可以用来把容器作为 Web 服务器使用,还可以通过网络让不同容器之间相互通信,Docker 默认使用 TCP 协议在容器之间进行网络通信,如果你需要 UDP,可以使用如下格式指定:

sudo docker run -ti --name web -p 80:80/udp net:v1.0 bash

容器互联

容器互联可以不用端口映射就可以让容器之间进行交互。容器互联会在源容器和接收容器之间创建一条安全隧道,接收容器可以看到源容器的信息。

首先,创建一个源容器:

sudo docker run -ti --name source net:v1.0 bash

然后运行另一个容器,使用--link 参数连接第一个容器:

sudo docker run -ti --name receiver --link source:sender net:v1.0 bash

这里的 --link source:sender 的意思是把名字为 source 的容器链接到别名 sender,然后你就可以在第二个容器里以 sender 这个名字和第一个容器通信,比如 ping sender。

这是因为,系统把这个别名加入到了 /etc/hosts 里面:

root@27089fd666ac:/# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.4	sender 45fe8823c336 source
172.17.0.3	27089fd666ac

ssh 登录容器

首先,运行一个容器:

sudo docker run -ti --name ssh -p 6667:22 net:v1.0 bash

然后在容器里面启动 ssh 服务:

service ssh start

查看我们的容器的 IP 地址:

ifconfig

假设为172.17.0.3,那么访问:

ssh root@172.17.0.3

然后就顺利进入容器了。

 

Docker 网络高级用法

本小节主要讲一点 Docker 网络的高级用法。

当 Docker 启动的时候,会在宿主主机上面创建一个名字为 docker0 的虚拟网桥,相当于一个软件交换机,并且,Docker 会随机分配一个未被占用的私有网段给 docker0 接口(具体原理在之后的“底层原理初探”讲解)。

docker network list

 你可以使用 Docker 组建自己的虚拟局域网。在此之前,首先看看 Docker 默认为我们创建的三个网络:bridge,none,host:

docker network list
NETWORK ID          NAME                DRIVER              SCOPE
7334ef3a9a0a        bridge              bridge              local
ed31c81055a0        host                host                local
90e4b19db0de        none                null                local

其中,bridge 是默认的网络模式docker0 是默认的网络,当我们在运行容器的时候,如果没有显式指定网络,那么我们的容器会被默认添加到 docker0 网络中,docker0 的模式正是 bridge。在我的电脑上,docker0 的网址是172.17.0.1,所以我们添加到 docker0 网络的容器的网址都是172.17.0.x。

none 模式翻译过来就是“无网络模式”,加到这个网络模式中容器,无法进行网络通信,我一般不使用。

host 模式将容器网络与宿主主机的网络直接相连通,这听起来不错,但是却破坏了容器的网络隔离,一般也很少使用。

虽然 Docker 为我们创建了一个 docker0 的默认网络,但是有时候我们希望定义自己的网络,使用如下指令可以创建一个名为 mynet 的网络:

sudo docker network create --driver bridge mynet

命令解释:

  • -driver后面的一项是网络模式,这里我们选 bridge;

最后一项 mynet 是我们网络的名字。

# docker network list
NETWORK ID          NAME                DRIVER              SCOPE
7334ef3a9a0a        bridge              bridge              local
ed31c81055a0        host                host                local
90e4b19db0de        none                null                local


# docker network create --driver bridge mynet

bf07bd076b1270996dfd3e9c29351b7df532c7a8ccd0f470b1b28ae8758e9deb

# docker network list
NETWORK ID          NAME                DRIVER              SCOPE
7334ef3a9a0a        bridge              bridge              local
ed31c81055a0        host                host                local
bf07bd076b12        mynet               bridge              local
90e4b19db0de        none                null                local

下面,使用 ifconfig 发现我们多了一个网络:

root@hongkong-web1:~# ifconfig
br-bf07bd076b12 Link encap:Ethernet  HWaddr 02:42:e3:16:4f:05  
          inet addr:172.18.0.1  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

docker0   Link encap:Ethernet  HWaddr 02:42:47:1d:ff:11  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:7266 errors:0 dropped:0 overruns:0 frame:0
          TX packets:10462 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:434277 (434.2 KB)  TX bytes:55208254 (55.2 MB)

eth0      Link encap:Ethernet  HWaddr 00:16:3e:00:43:91  
          inet addr:172.31.185.10  Bcast:172.31.191.255  Mask:255.255.240.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1832644 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1842516 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:459773459 (459.7 MB)  TX bytes:215285946 (215.2 MB)

现在,我们运行一个容器,并使用 --net 参数把这个容器添加到我们的 mynet 网络:

sudo docker run -ti --name netcontainer --net mynet net:v1.0 bash

使用这种方式,我们可以把容器添加到自定义网络。如下图所示:

 

删除网络指令:

sudo docker network rm mynet

Docker 可以通过 docker0 或者你自定义的网络桥接,让容器通过宿主主机的网络访问外部互联网,但是访问外部互联网还需要 DNS 配置,那么容器的 DNS 是怎么配置的呢?

其实,容器通过默认挂载宿主主机的3个相关配置文件来使用宿主主机的 DNS 配置,在容器里面使用 mount 命令可以看到相关信息:

这样,当宿主主机 DNS 信息发生变化的时候,容器的 DNS 配置会通过 /etc/resolv.conf 文件立刻得到更新。

如果你希望自己配置 DNS 信息,可以在使用 docker run 命令的时候加上 --hostname=HOSTNAME 参数设定容器的主机名,使用 --dns=IP_ADDRESS 添加 DNS 服务器到容器的 /etc/resolv.conf 文件中。

实例如下:

######创建自定义网络

  • root@root:~# docker network create --subnet=172.18.0.0/16 mynetwork

5142b9d98f693e204d297ffb397be8013ee39beda742831bf4684e8d69038f73

  • root@hongkong-web1:~# ifconfig

br-5142b9d98f69 Link encap:Ethernet  HWaddr 02:42:e6:6b:fc:98  
          inet addr:172.18.0.1  Bcast:172.18.255.255  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

docker0   Link encap:Ethernet  HWaddr 02:42:47:1d:ff:11  
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:7266 errors:0 dropped:0 overruns:0 frame:0
          TX packets:10462 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:434277 (434.2 KB)  TX bytes:55208254 (55.2 MB)

......

  • root@root:~#  docker network ls

NETWORK ID          NAME                DRIVER              SCOPE
7334ef3a9a0a        bridge              bridge              local
ed31c81055a0        host                host                local
5142b9d98f69        mynetwork           bridge              local
90e4b19db0de        none                null                local

######创建Docker容器

  • root@root:~# docker run -itd --name networkTest1 --net mynetwork --ip 172.18.0.2 centos:latest /bin/bash

 

[root@fee6577b0174 /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.2  netmask 255.255.0.0  broadcast 172.18.255.255
        ether 02:42:ac:12:00:02  txqueuelen 0  (Ethernet)
        RX packets 2019  bytes 11584764 (11.0 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1174  bytes 79965 (78.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1  (Local Loopback)
        RX packets 60  bytes 4705 (4.5 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 60  bytes 4705 (4.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

以上是关于Docker 学习笔记:第2节 Docker使用入门的主要内容,如果未能解决你的问题,请参考以下文章

Docker 学习笔记:第1节 初遇 Docker

Docker 学习笔记:第1节 初遇 Docker

十分钟了解Docker(我的Docker学习笔记)

DOCKER 学习笔记5 Springboot+nginx+mysql 容器编排

Docker学习笔记第一章:补充

Docker 与 K8S学习笔记—— 容器的操作(上篇)