玖叶教程网

前端编程开发入门

docker的那些事儿(dockers)

在Linux(Ubuntu)中安装docker

  • apt-get remove docker docker-engine docker.io containerd runc
  • apt update
  • apt-get install ca-certificates curl gnupg lsb-release
  • curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
  • add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
  • apt-get install docker-ce docker-ce-cli containerd.io
  • 中途出现问题的话,使用 sudo apt-get update 试试
  • systemctl start docker
  • apt-get -y install apt-transport-https ca-certificates curl software-properties-common
  • service docker restart
  • docker run hello-world
  • docker version

docker常用命令

帮助命令

docker version   # 显示Docker版本信息
docker info      # 显示Docker系统信息,包括镜像和容器数量
docker --help    # 帮助文档

镜像命令

docker images [options]                        # 列出本地主机上的镜像
# options
-a: 列出本地所有镜像 
-q: 只显示镜像id

docker search [image name] [options]           # docker search 某个镜像的名称(对应DockerHub仓库中的镜像)
# options
--filter=stars=50                              # 列出收藏数不小于指定值的镜像

docker pull [image name]:[tag]                 # 下载镜像

docker image rm -f [image name or image id]... # 删除一个或多个镜像
docker image rm -f $(docker images -aq)        # 删除本地全部镜像

docker image inspect [image id]                # 查看镜像元数据

docker history [image id or image name]        # 列出镜像的变更历史

docker login -u [username]                     # 登录dockerhub
docker push chrishi/mycentos:1.0               # 将镜像发布出去

容器命令

docker run [options] image [command]
# options
--name="Name"  # 给容器指定一个名字
-d             # 后台方式运行容器,并返回容器的id     
-i             # 以交互模式运行容器,通常和-t一起使用
-t             # 给容器重新分配一个终端,通常和-i一起使用
-P             # 随机端口映射(大写)
-p             # 指定端口映射(小写),一般可以有四种写法
                 ip:hostPort:containerPort 
     ip::containerPort 
               hostPort:containerPort (常用) 
                 containerPort
docker run -it centos /bin/bash  # 使用centos用交互模式启动容器, 在容器内执行/bin/bash命令
                                 # 使用exit退出容器

docker ps [options]  # 列出所有运行的容器
# options
-a                   # 列出当前所有正在运行的容器+历史运行过的容器
-l                   # 显示最近创建的容器
-n=?                 # 显示最近n个创建的容器
-q                   # 只显示容器编号

exit                 # 容器停止退出
ctrl+P+Q             # 容器不停止退出

docker start [container id or container name]  # 启动容器
docker restart [container id or container name]# 重启容器
docker stop [container id or container name]   # 停止容器
docker kill [container id or container name]   # 强制停止容器

docker rm [container id]        # 删除指定容器
docker rm -f $(docker ps -aq)   # 删除所有容器
docker ps -a -q|xargs docker rm # 删除所有容器

docker logs [options] [container id]  # 查看容器日志
# options
-t           # 显示时间戳
-f           # 打印最新的日志(follow log output)
--tail 数字  # 显示多少条

docker top [container id]  # 查看容器中运行的进程信息

docker inspect [container id] #查看容器的元数据

docker exec -it [container id] [bash shell] # 进入正在运行的容器(是在容器中打开新的终端,并且可以启动新的进程)
docker attach [container id]                # 直接进入容器启动命令的终端,不会启动新的进程

docker cp 容器id:容器内路径 目的主机路径  # 从容器内拷贝文件到主机上

docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名] # 从容器创建一个新的镜像

容器数据卷

挂载方式一:容器中直接使用命令来挂载

docker run -it -v 宿主机绝对路径目录:容器内目录 镜像名 /bin/bash

# eg
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

挂载方式二:通过Docker File 来挂载

# Dockerfile
FROM centos 
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"] 
CMD echo "-------end------" 
CMD /bin/bash 

docker build -t chrisshi/centos .

匿名和具名挂载

# 匿名挂载
-v 容器内路径 
docker run -d -P --name nginx01 -v /etc/nginx nginx
 # 匿名挂载的缺点,就是不好维护,通常使用命令 docker volume维护 
docker volume ls 

# 具名挂载 -v 卷名:/容器内路径
docker run -d -P --name nginx02 -v nginxconfig:/etc/nginx nginx
docker volume inspect nginxconfig   # 查看挂载的路径

# 怎么判断挂载的是卷名而不是本机目录名? 
不是/开始就是卷名,是/开始就是目录名

Dockerfile

基础知识

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层,并对镜像进行提交

构建步骤

  1. 编写Dockerfile文件
  2. docker build 构建镜像
  3. docker run

构建过程

  1. docker从基础镜像运行一个容器
  2. 执行一条指令并对容器做出修改
  3. 执行类似docker commit 的操作提交一个新的镜像层
  4. docker再基于刚刚提交的镜像运行一个新容器
  5. 执行Dockerfile中的下一条指令直到所有指令都执行完成

Dockerfile指令

FROM          # 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER    # 镜像维护者的姓名混合邮箱地址
RUN           # docker build 时需要运行的命令
EXPOSE        # 当前容器对外保留出的端口
WORKDIR       # 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ARG           # docker build 时Dockerfile文件中的变量
ENV           # docker run 时设置环境变量
COPY          # 拷贝文件和目录到镜像中
ADD           # 功能与COPY一样,但是多了自动解压文件的功能
VOLUME        # 容器数据卷,用于数据保存和持久化工作
CMD           # docker run 时要运行的命令,Dockerfile中可以有多个CMD指令,但只有最后一个生效
ENTRYPOINT    # docker run 时要运行的命令,和CMD一样
ONBUILD       # 当构建一个被继承的Dockerfile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发

CMD:Dockerfifile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换!

ENTRYPOINT: docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!

实例

背景:官方默认的centos镜像默认路径是 / ,默认不支持vim,默认不支持ifcofig

目的:使我们自己的镜像具备如下: 登录后的默认路径(/usr/local)、vim编辑器、查看网络配置ifconfig支持

# Dockerfile
FROM centos:7
MAINTAINER chris.shi<[email protected]>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum update
RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "--------end--------"
CMD /bin/bash

# 构建
# docker build -t 新镜像名字:TAG .
docker build -t my-centos:1.0 .

# 运行
# docker run -it 新镜像名字:TAG
docker run -it mycentos:1.0

# 列出镜像的变更历史
docker history [image id]

docker 网络讲解

理解docker0

原理

  • 每一个安装了docker的linux主机都有一个docker0的虚拟网卡。这个是桥接网卡,使用了veth-pair技术
root@chris-virtual-machine:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:7a:47:5a brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 192.168.32.128/24 brd 192.168.32.255 scope global dynamic noprefixroute ens33
       valid_lft 5529035sec preferred_lft 5529035sec
    inet6 fe80::7a87:6135:1c98:61a9/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:8c:f2:d0:2d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:8cff:fef2:d02d/64 scope link
       valid_lft forever preferred_lft forever
4: br-89830bc6a152: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:78:e0:07:c8 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/16 brd 192.168.255.255 scope global br-89830bc6a152
       valid_lft forever preferred_lft forever
  • 每启动一个docker容器,linux主机就会多一个虚拟网卡
# 我们启动了一个tomcat01(172.17.0.2),主机的ip地址多了一个 24: vethf840e91@if23
docker run -d -P --name tomcat01 tomcat
# 然后我们在tomcat01容器中查看容器的ip是 23: eth0@if24
docker exec -it tomcat01 ip addr

# 我们再启动一个tomcat02(172.17.03)观察
docker run -d -P --name tomcat02 tomcat
# 然后发现linux主机上又多了一个网卡 26: vethe152c3e@if25
# 我们看下tomcat02的容器内ip地址是 25: eth0@if26

# veth-pair 就是一对虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
# 正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备! 
# “Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等,以此构建出非常复杂的虚拟网络 结构,比如 OpenStack Neutron。
  • 测试tomcat01和tomcat02容器间是否可以互相ping通
root@0f3b19b75279:/usr/local/tomcat# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: icmp_seq=0 ttl=64 time=2.966 ms
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.164 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.171 ms

# 结论:容器和容器之间是可以互相访问的
  • 结论
tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0
任何一个容器启动默认都是docker0网络
docker默认会给容器分配一个可用ip
  • 小结
  • Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。 Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)
  • Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。

--Link

  • 思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们能不能使用服务名访问呢?

jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 --link 的操作!

# 我们使用tomcat02,直接通过容器名ping tomcat01,不使用ip, 发现是ping不通的
# 我们再启动一个tomcat03,但是启动的时候连接tomcat02
docker run -d -P --name tomcat03 --link tomcat02 tomcat
# 这个时候,我们就可以使用tomcat03 ping通tomcat02了
docker exec -it tomcat03 ping tomcat02
# 再来测试,tomcat03是否可以ping通tomcat01  失败
# 再来测试,tomcat02是否可以ping通tomcat03  反向也ping不通
  • 思考,这个原理是什么呢?我们进入tomcat03中查看下host配置文件
root@f86e6836e0a1:/usr/local/tomcat# 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.3      tomcat02 a263c1e773b2     # 发现tomcat2直接被写在这里
172.17.0.4      f86e6836e0a1

# 所以这里其实就是配置了一个 hosts 地址而已! # 原因:--link的时候,直接把需要link的主机的域名和ip直接配置到了hosts文件中了

--link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式

自定义网络

基本概念

root@chris-virtual-machine:~# docker network --help

Usage:  docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

所有网络模式

网络模式

配置

说明

bridge模式

--net=bridge

默认值,再docker网桥docker0上为容器创建新的网络栈

none模式

--net=none

不配置网络,用户可以稍后进入容器,自行配置

container模式

--net=container:name/id

容器和另外一个容器共享Network namespace。kubernetes中的pod就是多个容器共享一个Network namespace

host模式

--net=host

容器和宿主机共享Network namespace

用户自定义

--net=自定义网络

用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络

# 1. 删除原来的所有容器
 docker rm -f $(docker ps -aq)
# 2. 接下来我们来创建容器,但是我们知道默认创建的容器都是docker0网卡的
docker run -d -P --name tomcat01 --net bridge tomcat
# docker0网络的特点 1.它是默认的 2.域名访问不通 3.--link 域名通了,但是删了又不行
# 3. 我们可以让容器创建的时候使用自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
docker network ls
docker network inspect mynet
# 4. 我们来启动两个容器测试,使用自己的 mynet!
docker run -d -P --name tomcat-net-01 --net mynet tomcat
docker run -d -P --name tomcat-net-02 --net mynet tomcat
docker network inspect mynet
# 5. 我们来测试ping容器名和ip试试,都可以ping通
docker exec -it tomcat-net-01 ping 192.168.0.3
docker exec -it tomcat-net-01 ping tomcat-net-02

发现,我们自定义的网络docker都已经帮我们维护好了对应的关系

所以我们平时都可以这样使用网络,不使用--link效果一样,所有东西实时维护好,直接域名 ping 通

网络联通

docker0和自定义网络肯定不通,我们使用自定义网络的好处就是网络隔离

那关键的问题来了,如何让 tomcat-net-01 访问 tomcat1?

# 1. 启动默认的容器,在docker0网络下
docker run -d -P --name tomcat01 tomcat
docker run -d -P --name tomcat02 tomcat
# 2. 我们来测试一下!打通mynet-docker0
docker network connect mynet tomcat01
docker network inspect mynet  # 发现我们的tomcat01就进来这里了,tomcat01拥有了双ip
# 3. tomcat01 可以ping通了
docker exec -it tomcat01 ping tomcat-net-01
# 4. tomcat02 依旧ping不通,大家应该就理解了

结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER 连接

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言