Docker 学习笔记
赐我白日梦 人气:1安装
docker的安装最好需要centos内核版本在3.1及以上
查看系统内核版本
uname -r
安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
添加yum源
yum-config-manager --add-repo https:/https://img.qb5200.com/download-x/download.docker.com/linux/centoshttps://img.qb5200.com/download-x/docker-ce.repo
更新yum源
yum makecache fast
安装docker
yum install docker-ce -y
配置镜像加速
使用阿里云的镜像加速服务
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
在/etchttps://img.qb5200.com/download-x/docker 目录下创建damon.json添加下面 的信息,没有的话新建这个文件
sudo mkdir -p /etchttps://img.qb5200.com/download-x/docker
sudo tee /etchttps://img.qb5200.com/download-x/dockerhttps://img.qb5200.com/download-x/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://7djn00qt.mirror.aliyuncs.com"]
}
EOF
重新加载配置,重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker
常用的操作
查找镜像
docker search 关键字
如docker search mysql
拉取镜像
docker pull 镜像名
如:
查看系统中的镜像
docker images # 未来可能被删除
docker image list
docker image ls
删除镜像
docker rm -f 镜像id或者镜像名:TAG
查看镜像的元数据
docker inspect 镜像ID或者镜像名:TAG
运行镜像-->容器
docker run --name 容器名 -i -t -p 主机端口:容器端口 -d -v 主机目录:容器目录:ro 镜像ID或镜像名:TAG
--name 指定容器的名字
-i 以交互的模式运行容器
-t 分配一个伪终端(可以理解成bash命令行)
-p 端口映射,将主机的端口映射向容器内部的端口
-d 后台运行
-v 将主机目录(全路径)挂载到容器的目录中,比如可以让容器中的软件读取宿主机上的配置文件(默认rw读写,ro只读)
-v 注意它进行的目录级别的挂载,在使用-v启动容器之前,确保将容器目录中的配置文件拷贝到主机目录下
-v 根据需求修改主机目录配置文件,再启动时,容器会去主机目录下读取配置文件
-i -t 通常都被简写成-it, 容器中必须运行一个进程容器才不会自动退出,通常使用这个-it让容器运行bash,不让他退出
-v和-p都是可以重复使用的
命令中的tag和镜像id在上面的命令中都能找到
启动时可以通过指定容器的名字, 容器的名字是上图中的REPOSITORY, 如果不是lasted版本的需要添加上tag
查看容器列表
docker ps # 正在运行的
docker container list # 正在运行的
docker ps -a # 能看到停止状态Containner
容器中必须存在一个或者的进程容器才不会退出,上面的COMMAND表示的容器中指定的命令,一般都是通过这个命令去启动一个进程
停止容器
docker stop 容器ID或者容器名
重启容器
docker restart 容器ID或者容器名
删除容器
docker rm -f 容器id或者容器名
-f 表示强制删除
查看日志
docker logs 容器ID和容器名
进入正在运行的容器
docker container exec -it 指定的容器名或者容器的ID /bin/bash
# 顺序别乱
# 进入正在运行的容器并开启交互模式终端
# 这个正在运行中的容器可以理解成它是一个简化的linux
# /bin/bash 是固定的写法,标准的linux的shell,表示docker作为一个deaman在后台运行
退出容器
exit
拷贝文件
docker cp 主机文件路径 容器ID或者容器名:容器路径 将主机中的文件拷贝到容器中
docker cp 容器ID或者容器名 主机文件路径 # 将容器中的文件拷贝到主机中
这两条命令很常用,因为docker容器里面没有vim vi命令,不能直接修改它里面的配置文件
如果真的做配置文件的映射,别忘了将原来的Containner杀掉,然后从新启动image产生新的Containner
重新运行时需要在命令行上添加参数表示告诉docker来宿主机读取配置文件 参数: -v
获取容器的元信息
docker container inspect 容器ID或容器名
Dockerfile简介
点击进入dockerfile的官方地址
dockerfile其实一个文件,但是这个文件中存在着一些命令,docker会读取这个文件中的命令然后构建出命令对应的image
容器是分层的,就像下面的图一样
When you run an image and generate a container, you add a new writable layer (the “container layer”) on top of the underlying layers. All changes made to the running container, such as writing new files, modifying existing files, and deleting files, are written to this thin writable container layer
我们一运行镜像,这个镜像就会变成一个容器, 看看上图,可以发现我们手里的容器其实本身就是分层的,(然而容器是第三方提供的我们跟不用关系有多少层),但是我们能在现有分层的基础上继续添加可写的层, 比如我们可以创建新文件啊,修改现存的文件啊,或者删除现存的一些文件,并且这些修改对docker会生效
其实上面说的分层的概念还是有点模糊,就是说如果我们想构建自己的镜像的话,不用从0开始了,我们可以复用现有的仅可读的镜像,在此基础上构建我们的镜像,比如举个例子,我们jar包的执行需要借助java环境,那如果我们想构建一个镜像跑一个jar包,就得依赖现存的java 的镜像当成基础镜像
docker file中的每一行都会成为一层,所以官方推荐: dockerfile中的指令越少越好,越短越好
使用Dockerfile构建SpringBoot镜像
- 将jar包上传到linux上,并切换到jar包所在的目录
- 在jar所在的目录中创建如下的vim Dockerfile,添加如下内容
# 指定基础镜像,我们的jar包依赖java8的镜像
FROM java:8
# maintainer作者
LABEL maintainer=changwu
# 将可执行jar包复制到可执行目录的根目录下
ADD lawyer-lover-consumer-1.0-SNAPSHOT.jar /lawyer-lover-consumer-1.0-SNAPSHOT.jar
# 镜像要暴露的端口,如果要使用端口,docker run -p [端口]
EXPOSE 80
# entrypoint 在镜像运行为容器后执行的命令
ENTRYPOINT ["java","-jar","/lawyer-lover-consumer-1.0-SNAPSHOT.jar"]
构建
docker build -t myproject:v1 .
-t 跟镜像名和TAG
-f 跟Dockerfile的路径
. 指当前目录
运行
docker run --name myproject -p 9998:80 -d 镜像名:TAG
docker run --name myproject -P -d 镜像名:TAG
Dockerfile参数
命令 | 简介 |
---|---|
FROM | 设置镜像使用的基础镜像 |
MAINTAINER | 设置镜像的 |
LABEL | MAINTAINER的替代者,设置镜像的标签 |
EXPOSE | 暴露容器的端口 |
ADD | 构建镜像时,拷贝文件到容器中 |
COPY | 构建镜像时从宿主机拷贝文件到容器中 |
ENTRIPOINT | 设置容器启动后执行的命令 |
CMD | 设置容器启动后执行的命令 |
VOLUME | 设置挂载卷 |
ENV | 设置容器的环境变量 |
ARG | 设置系统的环境变量 |
USER | 设置运行RUN CMD ENTRYPOINT的用户名 |
WORKDIR | 设置RUN CMD ENTRYPOINT COPY ADD指令的工作目录 |
ONBUILD | 设置镜像的ONBUILD指令 |
STOPSIGNAL | 设置容器的退出信号量 |
FROM
Dockerfile中的第一个非注释行,用来指定基础镜像,默认情况下会先尝试从本地获取基础镜像,本地没有的话就会去DockerHub中拉取,常用的书写格式 如下:
这是官方推荐的基础镜像地址 : https://hub.docker.com/_/alpine/
FROM image
FROM image:tag
FORM image:@:digest
MAINTAINER
用来指定作者的信息,但是在未来的版本将会被弃用
LABEL
现在官方推荐的使用LABEL去描述镜像的各种元数据,比如向下面这样,支持同时设置多个label
# Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor1="ACME Incorporated"
LABEL vendor2=ZENITH\ Incorporated
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""
注意上面的细节: 带空格的字符串必须加引号或空格必须转义。内部引用字符(")也必须转义
并且官方不建议上面的书写格式(因为每一条指令都会生成一个镜像),而是建议我们向下面这样合并起来label
# Set multiple labels on one line
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
或者这样也行
# Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production="" \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"
ADD or COPY
ADD 和 COPY看起来很像,但是一般来说都会优先选择COPY,因为它比ADD更透明, COPY仅仅支持将本地的文件复制到容器中,使用ADD支持TAR文件和URL路径(网上文件的下载路径), 命令不能很好的却分 是从本地进行复制还是通过url从远程拉取文件
使用ADD时注意,如果是tar包的话,宿主机上的tar包拷贝到image中会被解压, 但是过URL下载链接的制作镜像时,tar包不会被自动解压, 而且容器中的目录最后需要加上/ 不然启动不起来
ENTRIPOINT or CMD
entrypoint和cmd 都是在指定容器启动后的命令
entrypoint两种格式
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2 (shell中执行)
ENTRYPOINT可以指定容器启动后执行的命令,当指定多个时,同样也只有最后一个命令会生效,并且它不能被docker run中指定的参数所覆盖
(不过可以这样进行覆盖docker run命令的--entrypoint参数可以覆盖ENTRYPOINT)
cmd的三种格式
CMD ["executable","param1","param2"] # 使用exec执行
CMD command param1 param2 # 在 /bin/sh 中执行
CMD ["param1","param2"] # 给ENTRYPOINT提供默认的参数
cmd可以指定容器启动时执行的命令,每个Dockerfile中 只能有一个CMD命令,如果写了多个CMD,只有最后一个会生效, 并且,用户在通过docker run 启动容器时添加的参数 会覆盖原CMD的命令
小结:
- 他们可以指定容器启动后执行的命令,并且当同时存在多个CMD或者多个ENTRYPOINT时,只有最一个会生效
- 当Dockerfile中同时存在CMD和ENTRYPOINT时.并且CMD又不是为了给ENTRYPOINT提供默认的参数,那么谁在最后谁生效
VOLUME
卷, 这个参数和我们启动容器时使用的docker run -v 宿主机目录:容器目录
类似这种挂载券操作, 下面命令中的挂载点其实是容器中的目录,宿主机中的目录会被随机生成
VOLUME mountpoint # 如 VOLUME https://img.qb5200.com/download-x/data1
举个应用的场景,当我们想将容器中mysql数据库中的数据同步到宿主机的目录下面时,我们可以使用VOLUME,这样配置后会随机在宿主机上创建一个目录存放数据
EXPOSE
指定容器和外部进行通信的端口以及协议, EXPOSE 可以指个端口. 默认的协议是tcp协议
语法:
EXPOSE <port>
EXPOSE 80/tcp 9999/udp
当我们运行镜像时,使用-p手动指定宿主机和容器的端口映射规则, 使用-P 的话,会自动完成-p的工作, 首先会自动的分配一个宿主机的端口, 然后将宿主机的端口映射到EXPOSE的端口上
ENV
类似于环境变量,在Dockerfile中通过ENV定义的环境变量,之后可以通过$variable_name
或者{variable_name}取出值使用
两种格式:
ENV <key> <value> # 一次只能指定一对k-v
ENV <kay>=<value> # 一行指定多个k-v, 如果中间有空格通过\转义,或者使用""标识, 而且\还可以表示换行
ARG
作用和ENV相仿,都可以类型指定环境变量,而且可以在docker build创建镜像的时候,使用 --build-arg=指定参数
来指定参数
Docker 网络模型
docker允许通过外部访问容器或者容器互联的方式提供网络服务, 安装docker deamon时,会自动安装一个docker网卡,叫做Docker0 (通多 ip addr 可以查看,如下图)
一个小例子
在开始Docker网络的笔记前,我想说这个真实的小例子,如果你精通网络方面的知识希望你在评论区指出我说的不对的地方
在说docker之前,我想说一个现实的例子: 我们学校想举办一场ACM区域赛,学校给了两个机房,每个机房都有一百多台电脑,老师的意思是将我们的CLP平台运行在内网中,在内网中举行这次比赛,于是我的同学开始筹划组建一个局域网,要组建一个内网,我们手里面有什么设备呢? 斐讯的路由器,还有机房的交换机.
其实说是搭建一个局域网感觉是有点花哨了,我们的最终目的是啥呢? 其实就是让所有的同学都连接一个路由器实现电脑机房的互联(就是可以通过ip相互访问到),但是路由器上有两种接口,lanip和wanip,如果本地的机器之间想互联的话,就使用lan口, wan口是用来连接外网使用的, 路由器上面lan口就4个,两个机房中两百个机器怎么互联呢? 还好我们有交换机
常见的内网网段: 10.X.X.X 100.X.X.X 192.168.X.X 172.16.X.X - 172.31.X.X
下面是路由器控制台配置lan口的图片
然后大家都去连接路由器的无限信号,看上图将DHCP关掉了,连接上路由器的网络后不能不会被分配一个随机的ip使用,于是我们就得自己去手动配置自己电脑的ipv4地址,像下面这样
上面我们配置了当前的局域网中当前机器的ip地址,两个机房中的ip地址不会存在重复的情况,并且他们都能都过ip经过交换机访问到彼此
**最后我们找一台虚拟机当成服务器,在上面启动Tomcat,跑我们的CLP,同学们通过ip+_端口来访问这个虚拟机上面的WebServer.就能欢快的比赛了**
为什么说这个例子呢? 其实这应该就是大家说的桥接模型,整个局域网中,所有的机器想互联就得在一个网段里面,就像上面的子网掩码限制了我们的网段是192.168.1.XXX (XXX的范围是1-254),同时处于这个网段的电脑之间是可以互联的,拥有自己的ip,并且路由器如果能连接外网,那么局域网中的电脑就能中继连接外网
说了这么多和Docker有什么关系呢? docker默认的网络模型就是桥接模型, 上图中的Docker0网卡是Docker deamon的虚拟网卡, 我们可不可以将docker demon想象成他是我们虚拟机里面的一个虚拟内网呢? 这个比喻就好比是下面这样
华为云ECS == 笔记本电脑
docker deamon == VMware Workstation Pro
Containner1 == VMware中的虚拟机1
Containner2 == VMware中的虚拟机2
Containner3 == VMware中的虚拟机3
就好比我们当初想让VMware中的虚拟机连接外网一样
docker container 其实就是一个极简的linux镜像,麻雀虽小五脏俱全啊...什么dns解析,路由表,host文件它都有, 每一个docker容器模式使用桥接的网络模型就意味着没个容器都有自己的ip地址, 宿主机和容器之间怎么通信呢? 这个问题就好比你的笔记本怎么和VMare中的虚拟机如何通信一样, 可以理解成docker将物理机上的网卡虚拟化成一个交换机,进而实现彼此互联
有啥不懂的欢迎关注计算机网络大佬前端大佬: https://home.cnblogs.com/u/camwang
docker网络中的核心概念
- 沙盒: Docker的沙盒可以让docker拥有完全独立的容器网络环境, 沙盒提供了端口socket,ip路由表,防火墙等内容
- 网络: 为了保证容器之间的安全通信, Docker的虚拟网络和宿主机的网络之间是隔离的,这里说的网络可以理解成docker内部的虚拟子网,Docker中的容器之间可以在这个虚拟子网中相互可见相互通信
- 端点: 容器通过这个端点实现和外网的通信,这个端点就是可控的突破封闭的网络环境的出入口
docker中存在四种网络模式 Bridge,Host,None,Containner
拓展网络模式解释: https://www.cnblogs.com/ggjucheng/archive/2012/08/19/2646007.html
[root@139 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
0dd04b1074d6 bridge bridge local
d3c5ff224f6d host host local
83a97a50d16f none null local
bridge 桥接模式
最直观的看bridge就是, 宿主机和容器各有各的ip,但是可以互联
我们在使用docker run命令时从来没有配置过添加参数配置docker的网络模式, 那是因为docker中默认使用桥接模式网络模式, 而且,bridge模式应该是可以满足大部分的需求
我们可以是要使用bridge自定义一些网络配置
修改主机名称(就像我们常改的host文件)
[root@139 ~]# docker run --name test1 -it --network bridge -h changwu --rm busybox:latest
/ # hostname
changwu
/ # 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 changwu
/ # cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 100.125.1.250
nameserver 100.125.136.29
options single-request-reopen
/ # nslookup -type=A www.baidu.com
Server: 100.125.1.250
Address: 100.125.1.250:53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 180.101.49.12
Name: www.a.shifen.com
Address: 180.101.49.11
---------命令详解------------
在busybox容器中查看这个容器的host文件,已经修改成我在启动参数规定的值了
也就是说,当前的容器会将changwu解析成前面的ip地址 172.17.0.3
你看这个容器和linux没啥区别,确实是一个极简的linux,而且它同样有自己的dns解析配置
上面的查看resolv.conf ,100.125.1.250是外往的地址
换句话说,当前的容器访问XXX.com域名时,先找本机host文件,找不到的话,就访问这个100.125.1.250 去解析
------参数详解--------
-h 主机名
-it 运行这个极简的bash
--network 网络模式
--rm 一旦退出容器就删除该容器
自定义DNS地址
[root@139 ~]# docker run --name test -it --network bridge --dns 8.8.8.8 --rm busybox
/ # cat /etc/resolv.conf
nameserver 8.8.8.8
options single-request-reopen
-------参 数解释-------
--dns 跟dns地址
更多命令使用 docker network --help 查看
host 宿主机网络模式
host网络模式和bridge桥接的区别就是 host模式中,虚拟机和主机共用一块网卡上网,这时候虚拟机和主机的之间相当于是一个机器, 容器启动后对外暴露的提供服务的端口直接绑定到注解对应的端口上, 容器的ip地址就是我的华为云ECS的公网ip
[root@139 ~]# docker run --name test -it --network host --rm busybox
/ # hostname
139.9X.92.X35
none
会形成一个全封闭的容器,没有网络配置,无法和外网互联
[root@139 ~]# docker run --name test -it --network none --rm busybox
/ # hostname
6511ba02c5e3
container
他和host模式很像, host模式会容器共享主机的ip, 这个container模式就是让当前容器共享另一个容器的 network namespace
[root@139 ~]# docker run --name test -it --network container:the_other_container --rm busybox
Docker 端口映射
-p (小写)的几种用法
- 指定容器的端口动态的映射到宿主机的端口上
[root@139 ~]# docker run --name mysql -d -p 3306 -e MYSQL_ROOT_PASSWORD=123123 mysql
291f7337a1ac0232d84eae4b3632bd044bcc433c7a0bafaf97b638a05ddddaf8
[root@139 ~]# docker port mysql
3306/tcp -> 0.0.0.0:32770
--------解释-----------
在宿主机上找一个动态的端口,映射到 Containner的 3306端口上
- 端口映射
[root@139 ~]# docker run --name mysql -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123123 mysql
eaa6bdb54df54419cce5866d5050fec8d1aba4d7d5b85ab41c3e41fd1887c6d0
[root@139 ~]# docker port mysql
3306/tcp -> 0.0.0.0:3306
--------解释-----------
成功的将宿主机上的3306端口映射到 mysql Containner的3306端口上
- 通过宿主机ip+端口, 映射到容器的指定端口上
[root@139 ~]# docker run --name mysql -d -e MYSQL_ROOT_PASSWORD=123123 -p 192.168.0.32:3306:3306 mysql
e1ef0d628415a41d6a122c78909cb63c00a788056395d64e667c496ac0c68cdc
[root@139 ~]# docker port mysql
3306/tcp -> 192.168.0.32:3306
- 指定宿主机的ip, 将容器中的指定端口映射到动态的宿主机端口
[root@139 ~]# docker run --name mysql -d -e MYSQL_ROOT_PASSWORD=123123 -p 192.168.0.32::3306 mysql
2f125488de4dbe4b5583baa46cbedb11a6b15cd38804c23815475d39a262dff5
[root@139 ~]# docker port mysql
3306/tcp -> 192.168.0.32:32768
-P (大写) 的用法
目的是暴露容器中的所有端口, 哪些端口呢? 就是我们在Dockerfile中通过Export指定的端口
Docker Compose 编排SpringCloud
将项目容器化后固然很方便,但是总不能真的就挨个去启动吧,其实是不用的,我们使用DockerCompose, 使用Componse我们可以在yml中去配置我们的服务,使用单行命令实现启动配置中的所有服务
下面的示例是使用Docker Compose编排我写的 一个法律助手的项目
下载安装
项目在github上面: https://github.comhttps://img.qb5200.com/download-x/docker/compose/releases
下载:
curl -L https://github.comhttps://img.qb5200.com/download-x/docker/compose/releaseshttps://img.qb5200.com/download-x/download/1.25.0-rc3https://img.qb5200.com/download-x/docker-compose-`uname -s`-`uname -m` -o /usr/local/binhttps://img.qb5200.com/download-x/docker-compose
给docket-compose 可执行的权限
chmod +x /usr/local/binhttps://img.qb5200.com/download-x/docker-compose
设置软链接
ln -s /usr/local/binhttps://img.qb5200.com/download-x/docker-compose /usr/binhttps://img.qb5200.com/download-x/docker-compose
验证是否安装
docker-compose version
卸载
rm /usr/local/binhttps://img.qb5200.com/download-x/docker-compose
思路: DockerComponse的配置文件和Dickerfile中的配置文件类似的, 它的格式的 yml
首先就是安排好jar包和文件的目录位置, 比如下图, 四个蓝色名称的目录中存放着不同功能的jar包,DockerComponse需要的配置文件 docker-componse.yml 也在这里面
docker-componse.yml 实战模板:
version: '2.1'
services:
eurekaserver:
image: eurekaserver:v1
ports:
- 10086:10086
lawyer-lover-consumer:
image: lawyer-lover-consumer:v1
ports:
- 8082:8082
lawyer-lover-main:
image: lawyer-lover-main:v1
ports:
- 8081:8081
lawyer-lover-zuul:
image: lawyer-lover-zuul:v1
ports:
- 10010:10010
输入命令进行自动编排
docker-compose up -d
-----------------------
-d 表示后台启动
结果: 看着自己写了这些天的项目上线了, 真的爽歪歪啊...
验证结果:
将本地镜像发布到阿里云仓库
如果你也想一处构建, 导出运行的话, 可以玩玩这个功能
网址: https://cr.console.aliyun.com/cn-hangzhou/repositories
- 将镜像推送到阿里云
# 登录阿里云的docker仓库
docker login --username=[用户名] registry.cn-hangzhou.aliyuncs.com
# 创建指定镜像的tag,归入某个仓库
docker tag [镜像ID] registry.cn-hangzhou.aliyuncs.com/huaan/huaan:[镜像版本号]
# 将镜像推送到仓库
docker push registry.cn-hangzhou.aliyuncs.com/huaan/huaan:[镜像版本号
- 拉取镜像到本地
docker pull registry.cn-hangzhou.aliyuncs.com/coldest7/mytom:v1
dokcer run --help
docker --help
docker network --help
dokcer Containner --help
docker image --help
加载全部内容