前言
新项目使用K8S部署,前端需要打Docker镜像,这里记录下学习Docker的笔记。
安装Docker
安装前删除旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc
安装依赖
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
添加 Docker 的科大 GPG 密钥
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
添加仓库
sudo add-apt-repository \
“deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \ $(lsb_release -cs) \ stable”
安装
1 | sudo apt-get update |
错误修改
没有使用sudo
时会出现下面的错,是当前用户不在docker组里面
1 | ubuntu@VM-0-8-ubuntu:~$ docker ps |
可以添加当前用户到docker组
1 | sudo gpasswd -a ubuntu docker |
配置镜像加速
1 | 创建目录 |
常用命令
镜像
docker images 查看所有镜像
1 | -a --all # 列表所有镜像 |
docker search 搜索镜像
docker pull 下载镜像
1 | docker pull [OPTIONS] NAME[:TAG|@DIGEST] |
docker rmi 删除镜像
1 | docker rmi -f 镜像ID #删除一个 |
容器
有镜像才有容器
docker run 运行容器
1 | docker run [OPTIONS] IMAGE [COMMAND] [ARG...] |
docker ps 查看容器
1 | docker ps #查看当前运行的容器 |
退出容器
1 | exit #直接容器停止并退出,有服务不停止? |
删除容器
1 | docker rm 容器ID # 删除指定容器,不能删除运行的容器,如果要删除 rm -f |
启动和停止容器
1 | docker start 容器ID #启动容器 |
常用命令
后台启动容器
1 | docker run -d 镜像名 |
查看日志
1 | docker logs 容器ID |
查看容器中进程信息
1 | docker top 容器ID |
查看容器的元数据
1 | docker inspect 容器ID |
进入当前正在运行的容器
1 | 进入后台运行的容器 |
从容器内拷贝文件到主机
1 | 容器在数据就在,不管它是否在运行 |
Commit 镜像
保存修改后的容器(保存当前容器的状态),可以通过commit
提交,获取一个镜像。
1 | docker commit -a="davis" -m="add webapps" tomcat01 tomcat01:1.0 |
容器数据卷
容器不在了,容器中的数据也就不在了。容器之间可以数据共享,Dokcer产生的数据,同步到本地,这就是卷技术,目录的挂载,将容器内的目录,挂载到Linux上面。
同步后,容器停止了,修改主机目录还是可以同步到容器中的,也就是说容器还在,两个目录都是同步的。(双倍存储?)
1 | docker run -v 主机目录:容器目录 |
具名和匿名挂载
不是
/
开头的不是目录,是一个名称。指定目录的,和容器目录同步。
不指定目录的,即是具名或是匿名挂载的,目录都在默认位置。
/var/lib/docker/volumes/[具名|匿名(一串ID)]/_data
1 | 只标明容器目录,没有写主机目录,是匿名挂载 |
dockerfile挂载
1 | 构建一个镜像 |
数据卷容器
容器之间的目录同步 --volumes-from 容器名称或ID
1 | 启动容器1 |
这三个容器之间的数据卷目录是同步的,只要其中一个容器的数据卷目录内容修改,其他两个容器的数据卷目录也会同步修改。且这种同步是拷贝式的同步,也就说这三个容器只要还有一个容器在,其中的数据就会存在,只有三个容器都删除了,数据才会被删除。当前这些数据可以同步到本地,就会持久化到本地了,容器不在数据也都还在。
Dockerfile
dockerfile是用来构建docker镜像的文件,命令参数脚本。
构建步骤:
1、编写一个dockerfile
2、docker build 构建一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(DockerHub/其他镜像仓库)
前提
1、每个保留关键字(指令)都必须是大写字母
2、执行从上到下顺序执行
3、# 表示注释
4、每个指令都会创建提交一个新的镜像层,并提交。
镜像层:每个镜像都是有一层层(layer)组成的。
指令
1 | FROM # 基础镜像,一切从这里开始 |
构建镜像
编写一个centos编辑,添加 vim 和net-tools
1 | dockerfile1文件 |
错误修改
这里碰到一个问题,就是主机系统是ubuntu
而写dockerfile时,写了RUN apt-get install -y vim
运行构建时报错:/bin/sh: apt-get: command not found
,最后排查发现,这个镜像基础是centos
,要改成RUN yum -y install vim
就没问题了。
查看镜像构建历史
1 | docker history 镜像名称:[tag]或镜像ID |
CMD和ENTRYPOINT的区别
CMD
是启用容器时,在容器里执行的命令,只能有一个,也就是说最后一个生效,不能追加命令
1 | cmd-dockerfile 测试 |
ENTRYPOINT
是启用容器时,在容器里执行的命令,只能有一个,也就是说最后一个生效,这个可以追加命令
1 | entrypoint-dockerfile 测试 |
注意:
ENTRYPOINT ["ls", "-l"]
和ENTRYPOINT ls
这两种写法是有区别的。前者的可以追加命令;后者不可以追加命令,追加命令参数错误也不会报错。
区别
都是在启用容器时运行的命令。
对于CMD
来说,追加命令时会覆盖CMD
的命令。
1 | CMD ["pwd"] |
对于ENTRYPOINT
,追加的命令会当作参数追加到ENTRYPOINT
的命令里。
1 | ENTRYPOINT ["ls", "-l"] |
混写
根据区别可以这样写,执行时给一个默认参数,运行时可以覆盖这个参数,也可以不写。
1 | 需要执行的命令 |
Docker网络
清空所有镜像和容器后看下安装了docker
主机上的网络情况
1 | ubuntu@VM-0-8-ubuntu:~/dockerfile# ip addr |
看下运行一个容器后,主机的网络情况和这个容器内的网络情况
1 | 运行一个容器 |
再起一个容器看下,两个容器间的网络是否可以ping
通
1 | 起一个容器 |
原理
我们每启动一个docker容器,docker就会给docker容器分配 一个IP,我们只要安装了docker,就会有一个docker0的网卡。每个容器和主机通信是通过veth-pair技术。容器间是通过docker0网络作网桥来进行通信的。
每个容器的网卡都是一对对的。
通过veth-pair
就是一对虚拟设备接口,它们都是成对出现的,一端连着协议栈,一端彼此连着。
tomcat01 -> veth-pair -> docker0 -> veth-pair -> tomcat02
只要删除容器,对应的网卡也会删除的。
link
现有一个场景,编写了一个微服务,
database url=ip
,项目不重启,数据库IP
换掉了,我们希望可以处理这个问题,可以通过名字来进行访问容器。
1 | 再启动一个容器tomcat03 |
运行容器通过 --link
连接到另一个容器时,是怎么可以ping
的呢,但是反过来就不行呢?
1 | tomcat02的 hosts配置 |
--link
是通过配置hosts
映射去的。这个配置是单向的,如果两个都想通过名称 ping
可以再配置这个映射关系。现在不建议使用这个。
自定义网络
查看docker所有网络
1 | root@VM-0-8-ubuntu:~/dockerfile# docker network ls |
网络模式
bridge:桥接模式 docker默认
none: 不配置网络
host:和宿主机共享网络
container:容器网络连通(用的少,局限很大)
1 | 默认的网络 --net bridge |
我们自定义的网络docker都已经帮我们维护好了对应的关系,而docker0,则需要自己维护。
网络连通
在docker0的网络里,有一个容器tomcat01,这个容器怎么连接到mynet的网络呢?
1 | 测试下,并不能ping 通 |
试下这个命令
1 | 把 tomcat01 连接到 mynet网络 |
tomcat01加到mynet里后,这个容器就有两个IP了,就像云主机一样,一个内网IP,一个公网IP。
这个容器可以在两个网络里通信了。