网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
2. 测试运行一个tomcat的容器,端口映射到主机的3355
https://hub.docker.com/_/tomcat
# 下载镜像再启动
docker pull tomcat
# 启动运行
docker run -d -p 3355:8080 --name tomcat01 tomcat
# 访问此容器会报错404,是因为tomcat官网镜像没有webapps,镜像源把所有镜像不必要的都剔除了,默认是最小可运行环境
# 进入容器,将默认的webapps.dist的内容拷贝一份到webapps目录下
[root@k8s-master ~]# docker exec -it tomcat01 /bin/bash
root@23e4e460879b:/usr/local/tomcat# cp -a webapps.dist/\* webapps/
# 再一次访问就成功了
[root@k8s-master ~]# curl -I 127.0.0.1:3355
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 19 Jun 2020 03:39:34 GMT
每次改动服务配置文件,都需要进入容器内部,十分麻烦,我们可以在容器外映射一个路径,达到在宿主机修改文件内容,容器内部就可以自动同步修改,就是数据卷的操作
3. 测试部署一套elasticsearch+kibana的日志监控的容器
https://hub.docker.com/_/elasticsearch
启动一台es容器
# es暴露的端口很多
# es十分耗内存
# es数据一般需要放置到安全目录挂载
# 启动elasticsearch
[root@k8s-master ~]# docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2
#访问
[root@k8s-master ~]# curl 127.0.0.1:9200
{
"name" : "7426e97975a1",
"cluster\_name" : "docker-cluster",
"cluster\_uuid" : "aNGISnU9QZm3qQw9obQiPg",
"version" : {
"number" : "7.6.2",
"build\_flavor" : "default",
"build\_type" : "docker",
"build\_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build\_date" : "2020-03-26T06:34:37.794943Z",
"build\_snapshot" : false,
"lucene\_version" : "8.4.0",
"minimum\_wire\_compatibility\_version" : "6.8.0",
"minimum\_index\_compatibility\_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
使用命令dcker stats
查看es容器的内存占用情况太大
# 关闭刚刚启动的es容器,增加内存的限制,修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES\_JAVA\_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
[root@k8s-master ~]# curl 127.0.0.1:9200
{
"name" : "66fdfb9147aa",
"cluster\_name" : "docker-cluster",
"cluster\_uuid" : "7vONQG4HSjKXdtpMmEzbIg",
"version" : {
"number" : "7.6.2",
"build\_flavor" : "default",
"build\_type" : "docker",
"build\_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build\_date" : "2020-03-26T06:34:37.794943Z",
"build\_snapshot" : false,
"lucene\_version" : "8.4.0",
"minimum\_wire\_compatibility\_version" : "6.8.0",
"minimum\_index\_compatibility\_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
启动一台kibana容器
# 运行一台kibana7.6.2的容器,并添加到elasticsearch容器的网络中,使用--link或者创建自定义网络
docker run -d --name kibana --link elasticsearch -p 5601:5601 kibana:7.6.2
# 访问查看;选择一个样本数据进行测试是否与es连接
五、Docker可视化面板
# Portainer
基于Go,是一个轻量级的图形化界面管理工具,可轻松管理Docker主机。
# Rancher
开源的企业级容器管理平台,Rancher提供了在生产环境中使用管理Docker和Kubernetes的全栈化容器部署与管理平台。(CICD)
# cAdvisor
Google开发的容器监控工具, 会显示当前容器的资源使用情况,包括 CPU、内存、网络、文件系统等,显示容器列表。
1. 启动一台portainer容器(不常用)
[root@k8s-master ~]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
访问8088端口 http://192.168.0.10:8088
2.Rancher
Rancher
是一个开源的企业级容器管理平台。通过Rancher
,企业不必自己使用一系列的开源软件去从头搭建容器服务平台。Rancher
提供了在生产环境中使用管理Docker
和Kubernetes
的全栈化容器部署与管理平台。
docker run -d --restart=unless-stopped -p 81:80 -p 443:443 rancher/rancher:v2.0.0
docker logs -f rancher
3. cAdvisor
cAdvisor
是Google
开发的容器监控工具。
- 监控 Docker Host cAdvisor 会显示当前 host 的资源使用情况,包括 CPU、内存、网络、文件系统等。
- 监控容器 点击 Docker Containers 链接,显示容器列表。点击某个容器,比如 sysdig,进入该容器的监控页面。
以上就是 cAdvisor 的主要功能,总结起来主要两点:
- 展示 Host 和容器两个层次的监控数据。
- 展示历史变化数据。
由于cAdvisor
提供的操作界面略显简陋,而且需要在不同页面之间跳转,并且只能监控一个 host,这不免会让人质疑它的实用性。但 cAdvisor 的一个亮点是它可以将监控到的数据导出给第三方工具,由这些工具进一步加工处理。
我们可以把 cAdvisor 定位为一个监控数据收集器,收集和导出数据是它的强项,而非展示数据。 cAdvisor 支持很多第三方工具,其中就包括Prometheus`。
docker run -d \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--volume=/dev/disk/:/dev/disk:ro \
--publish=8080:8080 \
--detach=true \
--name cadvisor google/cadvisor:latest
六、Docker镜像讲解
1. Docker镜像加载原理
UnionFS(联合文件系统)
下载镜像时看到的一层层的就是这个!
UnionFS(联合文件系统)
是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。UnionFS是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
2. Docker commit定制镜像
docker不建议再通过这种方式构建镜像;具体原因如下
手工创建,容易出错,效率低并且可重复性弱。
无法对镜像进行审计,存在安全隐患。
学习commit定制镜像的原因:
dockerfile构建镜像,底层也是docker commit一层一层构建新镜像的,学习的目的是更加深入地理解构建过程和镜像分层结构。
三个步骤
- 运行容器
- 修改容器
- 将容器保存为新的镜像
# 第一步: 启动运行一个官方镜像的tomcat容器
[root@k8s-master ~]# docker run -it -d -p 8080:8080 --name tomcat02 tomcat
[root@k8s-master ~]# docker exec -it tomcat02 /bin/bash
# 第二步: 修改内容,将默认的webapps.dist/下内容复制到webapps下
root@81fd44790b38:/usr/local/tomcat# cp -a webapps.dist/\* webapps/
# 第三步: commit提交
--a #是指定修改的作者
--m #是记录本次修改的内容
[root@k8s-master ~]# docker commit -a "lichenxing" -m "cp -a webapps.dist/\* webapps/" tomcat02 tomcat02:V1.0
sha256:405a3c097a00380667ab5e3d4ed30458e5483cbb3182640c9275b2f82bc15f5d
# 第四步: 查看提交的镜像
[root@k8s-master ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 V1.0 405a3c097a00 34 seconds ago 652MB
tomcat latest 2eb5a120304e 9 days ago 647MB
七、Dokcer数据卷
容器的持久化和同步操作!容器间也是可以数据共享的!
容器删除后,数据还在主机上保存。
1. 使用数据卷
# 方式一: 直接使用命令挂载 -v
docker run -it -v 主机目录:容器目录
[root@k8s-master ~]# docker run -it -v /home/ceshi/:/home centos /bin/bash
[root@06b7f2dc16ec /]# ls /home/
# 容器挂载的/home/ceshi目录自动生成
[root@k8s-master ~]# ll /home/
total 0
drwxr-xr-x. 2 root root 6 Jun 19 16:36 ceshi
# 查看容器的详细信息(Mounts部分)
[root@k8s-master ~]# docker inspect 06b7f2dc16ec
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi", # 主机内的地址
"Destination": "/home", # docker容器内的地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
# 主机目录和容器目录都为空,在容器内添加文件
[root@06b7f2dc16ec /]# cd /home/
[root@06b7f2dc16ec home]# touch test.java
# 在主机上查看,已经同步过来了
[root@k8s-master ~]# ll /home/ceshi/
total 0
-rw-r--r--. 1 root root 0 Jun 19 16:43 test.java
# 在主机上追加文件内容
[root@k8s-master ~]# echo {a..z} > /home/ceshi/test.java
# 在容器内查看文件
[root@06b7f2dc16ec home]# cat test.java
a b c d e f g h i j k l m n o p q r s t u v w x y z
修改只需要在主机本地修改即可,容器可以自动同步。
补充:
使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去,如果使用mount时,宿主机中没有这个文件会报错,而不是像-v,没有这个文件也会自动创建。
# 挂载一个主机目录作为数据卷:(-v 和 --mount的对比)
docker run -d -P --name web \
# -v /src/webapp:/opt/webapp \
--mount type=bind,source=/src/webapp,target=/opt/webapp \
training/webapp \
python app.py
上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp目录。这个功能在进行测试的时候十分方便,比如用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,以前使用 -v 参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount 参数时如果本地目录不存在,Docker 会报错。
# Docker 挂载主机目录的默认权限是 读写,用户也可以通过增加readonly指定为只读。
docker run -d -P --name web \
# -v /src/webapp:/opt/webapp:ro \
--mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \
training/webapp \
python app.py
# 挂载一个本地主机文件作为数据卷:--mount标记也可以从主机挂载单个文件到容器中
docker run -it \
# -v /root/.bash\_history:/root/.bash\_history \
--mount type=bind,source=/root/.bash_history,target=/root/.bash_history \
ubuntu:17.10 \
bash
# 这样就可以记录在容器输入过的命令了。
root@2affd44b4667:/# history
1 ls
2 history
2. 安装MySQL
https://hub.docker.com/_/mysql
# 下载mysql5.7的官方镜像
docker pull mysql:5.7
# 运行一台mysql容器 (需要设置mysql密码; 映射配置文件和数据文件;通过官方镜像仓库查看启动容器的命令)
[root@k8s-master ~]# 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
0d709657652353d906f710118144ea401c6ce539c825abd2aa019e889278944c
#查看主机映射目录
[root@k8s-master home]# ls
ceshi lcx mysql
[root@k8s-master home]# cd mysql/
[root@k8s-master mysql]# ls
conf data
[root@k8s-master mysql]# ls data/
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem
通过本地第三方工具 SQLyog登陆mysql容器
新建一个数据库 test
# 查看主机映射目录也已经同步了test库目录
[root@k8s-master mysql]# ls data/
auto.cnf client-key.pem ib_logfile1 private_key.pem sys
ca-key.pem ib_buffer_pool ibtmp1 public_key.pem test
ca.pem ibdata1 mysql server-cert.pem
client-cert.pem ib_logfile0 performance_schema server-key.pem
3. 容器数据持久化
# 将容器删除后,数据已经保留下来了
[root@k8s-master ~]# docker rm -f mysql01
mysql01
[root@k8s-master mysql]# ls data/
auto.cnf client-key.pem ib_logfile1 private_key.pem sys
ca-key.pem ib_buffer_pool ibtmp1 public_key.pem test
ca.pem ibdata1 mysql server-cert.pem
client-cert.pem ib_logfile0 performance_schema server-key.pem
4. 具名和匿名挂载
匿名挂载:没有名字
# 启动一个nginx容器, 选择随机端口和随机挂载路径(只写了容器内的路径,没有写容器外的路径)
[root@k8s-master ~]# docker run -d -P --name nginx01 -v /etc/nginx nginx:latest
# 查看所有卷的情况(都是匿名卷,没有名字)
[root@k8s-master ~]# docker volume ls
DRIVER VOLUME NAME
local 6350e9d05a6611859fd3de283d1ea41eb234fc8720ec2d7a415d343ebc4e8de4
local a1b15cc90674c1d69f2f77e3b35543886d4f7ac40975f3dffe200df64e8e9b64
local bd43717a0bbfebd513b69fafa7ec3824805136b9ed7afd57605bfd3fedfd5662
local e8c6ff6336476cd8bbd65bee93e18ce1c073ab7901631d55312421f40fbde38d
local f2ecc7f10858285cda52f3a87bcc5e845f0de90785c56235744c9380cb7872cf
具名挂载:拥有名字
# 再启动一个nginx容器
[root@k8s-master ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx:latest
c446916349eefb151bf29f8ab657458e16deee7a46d65a3afa72b75a0ea30612
# 查看所有卷的情况(有名字为juming-nginx的卷)
[root@k8s-master ~]# docker volume ls
DRIVER VOLUME NAME
local 6350e9d05a6611859fd3de283d1ea41eb234fc8720ec2d7a415d343ebc4e8de4
local a1b15cc90674c1d69f2f77e3b35543886d4f7ac40975f3dffe200df64e8e9b64
local bd43717a0bbfebd513b69fafa7ec3824805136b9ed7afd57605bfd3fedfd5662
local e8c6ff6336476cd8bbd65bee93e18ce1c073ab7901631d55312421f40fbde38d
local f2ecc7f10858285cda52f3a87bcc5e845f0de90785c56235744c9380cb7872cf
local juming-nginx
# 查看具名挂载卷的路径
[root@k8s-master ~]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2020-06-19T17:52:09+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/\_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
所有的docker容器内的卷,没有指定目录的情况下都是在
/var/lib/docker/volumes/xxx/_data
下
通过具名挂载可以方便的找到我们的卷,大多数情况在使用的是具名挂载
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载?
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
扩展:
# 通过 -v 容器内路径:ro/rw 改变读写权限
ro readonly #只读
rw readwrite #可读可写
# 一旦设置了容器的读写权限,容器对我们挂载出来的内容就会有了权限了。
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx:latest
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx:latest
# ro 只要看到ro就说明此路径是只能通过宿主机来操作,容器内部是无法操作修改的!
5. Dockerfile的基础操作
dockerfile 就是用来构建docker镜像的构建文件! 命令脚本。
# 创建一个存放dockerfile文件的目录
mkdir -p /home/docker-test-volume
# 编写一个dockerfile,生成镜像(指令都为大写)
# 每行命令,就是镜像的一层!
[root@k8s-master docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
# 生成dockerfile文件
[root@k8s-master docker-test-volume]# docker build -f dockerfile1 -t lichenxing/centos:1.0 ./
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 831691599b88
Step 2/4 : VOLUME ["volume01","volume02"]
---> Running in 9a58f0ee53e5
Removing intermediate container 9a58f0ee53e5
---> 494b993538b5
Step 3/4 : CMD echo "----end----"
---> Running in 380c5748e66a
Removing intermediate container 380c5748e66a
---> 6f77f010dee6
Step 4/4 : CMD /bin/bash
---> Running in 002cd526e782
Removing intermediate container 002cd526e782
---> 62fd78da2572
Successfully built 62fd78da2572
Successfully tagged lichenxing/centos:1.0
# 查看生成的镜像
[root@k8s-master docker-test-volume]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
lichenxing/centos 1.0 62fd78da2572 43 seconds ago 215MB
# 使用生成的镜像创建一台容器
[root@k8s-master docker-test-volume]# docker run -it lichenxing/centos:1.0 /bin/bash
[root@1af48762856e /]#
# 查看目录,可以看到在dockerfile中自动挂载的数据卷
[root@1af48762856e /]# ls -l
total 0
lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x. 5 root root 360 Jun 23 03:31 dev
drwxr-xr-x. 1 root root 66 Jun 23 03:31 etc
drwxr-xr-x. 2 root root 6 May 11 2019 home
lrwxrwxrwx. 1 root root 7 May 11 2019 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 May 11 2019 lib64 -> usr/lib64
drwx------. 2 root root 6 Jun 11 02:35 lost+found
drwxr-xr-x. 2 root root 6 May 11 2019 media
drwxr-xr-x. 2 root root 6 May 11 2019 mnt
drwxr-xr-x. 2 root root 6 May 11 2019 opt
dr-xr-xr-x. 130 root root 0 Jun 23 03:31 proc
dr-xr-x---. 2 root root 162 Jun 11 02:35 root
drwxr-xr-x. 11 root root 163 Jun 11 02:35 run
lrwxrwxrwx. 1 root root 8 May 11 2019 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 May 11 2019 srv
dr-xr-xr-x. 13 root root 0 Jun 23 01:36 sys
drwxrwxrwt. 7 root root 145 Jun 11 02:35 tmp
drwxr-xr-x. 12 root root 144 Jun 11 02:35 usr
drwxr-xr-x. 20 root root 262 Jun 11 02:35 var
drwxr-xr-x. 2 root root 6 Jun 23 03:31 volume01 #生成镜像时自动挂载的数据卷目录
drwxr-xr-x. 2 root root 6 Jun 23 03:31 volume02 #生成镜像时自动挂载的数据卷目录
## 这两个卷一定有一个与外部同步的目录
# 在卷目录下创建一个文件
[root@1af48762856e /]# cd volume01/
[root@1af48762856e volume01]# touch container.txt
# 在宿主机上查看此容器的元数据可以看到卷挂载到了外部的某个目录下
[root@k8s-master docker-test-volume]# docker inspect 1af48762856e
...
"Mounts": [
{
"Type": "volume",
"Name": "588dd712d0817140680bd2d7fad6d85bf837cbf9f1ad8c435d06ff98d076f259",
"Source": "/var/lib/docker/volumes/588dd712d0817140680bd2d7fad6d85bf837cbf9f1ad8c435d06ff98d076f259/\_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "fbd1a9f5c760ef7b592c4b31aaaa3ab4887d650b40397476012d4d942b151bc6",
"Source": "/var/lib/docker/volumes/fbd1a9f5c760ef7b592c4b31aaaa3ab4887d650b40397476012d4d942b151bc6/\_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
# 可以看到volume01的挂载目录是路径,cd切换到目录下查看已经同步了创建的文件
/var/lib/docker/volumes/fbd1a9f5c760ef7b592c4b31aaaa3ab4887d650b40397476012d4d942b151bc6/_data/
[root@k8s-master _data]# ll
total 0
-rw-r--r--. 1 root root 0 Jun 23 11:35 container.txt
通常构建自己的镜像时,没有挂在卷,要手动镜像挂载 -v 卷名:容器内路径
6. 数据卷容器
创建三台容器来进行测验数据卷共享 (使用刚刚通过dockerfile生成的镜像)
--volumes-from # 只要通过此参数,则可以实现容器间的数据共享
# 创建第一台容器docker01,挂载的数据卷下没有内容
[root@k8s-master ~]# docker run -it --name docker01 lichenxing/centos:1.0
[root@eac7afb4cb11 /]# ls -l
total 0
....
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume01
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume02
[root@eac7afb4cb11 /]# ls volume01
[root@eac7afb4cb11 /]# ls volume02
# 创建的第二台容器docker02,挂载的为docker上的数据卷,也没有内容
[root@k8s-master ~]# docker run -it --name docker02 --volumes-from docker01 lichenxing/centos:1.0
[root@a493d7a3d2ca /]# ls -l
total 0
....
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume01
drwxr-xr-x. 2 root root 6 Jun 23 05:54 volume02
[root@a493d7a3d2ca /]# ls volume01
[root@a493d7a3d2ca /]# ls volume02
# 在docker01容器上的数据卷目录创建文件
[root@k8s-master ~]# docker attach docker01
[root@eac7afb4cb11 /]# touch /volume01/docker01
# 在docker02容器上查看,docker01的数据卷目录下文件也已经同步过来了
[root@k8s-master ~]# docker attach docker02
[root@a493d7a3d2ca /]# ls /volume01/
docker01
# 创建第三台容器docker03,将docker01的数据卷挂载; 并且再创建一个docker03文件
# 可以发现容器docker01上的数据卷内容都同步了
[root@k8s-master ~]# docker run -it --name docker03 --volumes-from docker01 lichenxing/centos:1.0
[root@336c364cb4fa /]# ls -l /volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
[root@336c364cb4fa /]# touch /volume01/docker03
# 在容器docker01上查看也同步了
[root@k8s-master ~]# docker attach docker01
[root@eac7afb4cb11 /]# ls -l volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
-rw-r--r--. 1 root root 0 Jun 23 06:07 docker03
删除容器docker01后,其他容器的数据卷内容没有丢失-拷贝机制
[root@k8s-master ~]# docker rm -f docker01
docker01
[root@k8s-master ~]# docker attach docker02
[root@a493d7a3d2ca /]# ls -l /volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
-rw-r--r--. 1 root root 0 Jun 23 06:07 docker03
[root@a493d7a3d2ca /]# read escape sequence
[root@k8s-master ~]# docker attach docker03
[root@336c364cb4fa /]# ls -l /volume01/
total 0
-rw-r--r--. 1 root root 0 Jun 23 06:01 docker01
-rw-r--r--. 1 root root 0 Jun 23 06:07 docker03
[root@336c364cb4fa /]# read escape sequence
可以运用在多个mysql实现数据共享
# 例子 mysql01
[root@k8s-master ~]# docker run -d -p 3310:3306 -v /etc/mysql/conf.d -v /var/lib/mysql -e MYSQL\_ROOT\_PASSWORD=123456 --name mysql01 mysql:5.7
# 例子 mysql02; 挂载mysql01的数据卷
[root@k8s-master ~]# docker run -d -p 3310:3306 -e MYSQL\_ROOT\_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
结论
- 容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
- 一旦持久化到本地目录,本地的数据是不会删除的。
九、Dockerfile
1. Dockerfile介绍
dockerfile 就是用来构建docker镜像的构建文件! 命令脚本!
构建步骤:
- 编写一个dockerfile文件
- docker build构建成为一个镜像
- docker run 运行镜像
- docker push 发布镜像(dockerHub、私有仓库)
很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!
2. Dockerfile构建
基础知识
- 每个指令都必须是大写字母
- 执行从上到下顺序执行
- "#"表示注释
- 每一个指令都会创建提交一个新的镜像层,并提交!
- Dockerfile是面向开发,我们以后要发布项目,做镜像,就需要编写dockerfile文件。
- Docker镜像逐渐成为企业交付的标准。
- Dockerfile :构建文件,定义了一切的步骤,源代码。
- DockerImages:通过DockerFile构建生成的镜像,最终发布和运行的产品,原来是jar包 war包
- Docker容器:容器就是镜像运行起来提供的服务器
3. Dockerfile的指令
FROM #指定基础镜像
MAINTAINER #指定镜像创建者信息(姓名+邮箱)
RUN #执行构建命令
CMD #设置容器启动时执行的操作(只有最后一个会生效,可被替代)
ENTRYPOINT #设置容器启动时执行的操作(可以追加命令)
USER #设置容器的用户
EXPOSE #指定容器需要映射到宿主机的端口
ENV #用于设置环境变量
ADD #从src复制文件到容器的dest路径(会自动解压tar包)
VOLUME #指定挂载点
WORKDIR #工作目录
ONBUILD #在子镜像中执行,构建一个被继承,就会运行此指令,触发指令
COPY #类似ADD,将文件拷贝到镜像中(不会解压tar包)
4. 自己写一个Dockerfile文件构建镜像
Docker Hub中,99%镜像都是从这个基础镜像
FROM scratch
过来的,然后配置需要的软件和配置进行构建。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。如果你以scratch
为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。有的人可能感觉很奇怪,没有任何基础镜像,我怎么去执行我的程序呢,其实对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch
会让镜像体积更加小巧。
# 创建一个存放dockerfile文件的目录
mkdir -p /home/dockerfile
cd /home/dockerfile/
# 编写dockerfile文件
[root@k8s-master dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER lichenxing<245684979@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash
# 进行构建
#docker build "."最后的"."号,其实是在指定镜像构建过程中的上下文环境的目录
docker build -f [dockerfile文件路径] -t 镜像名:[tag] .
[root@k8s-master dockerfile]#docker build -f mydockerfile-centos -t mycentos:0.1 .
....
Successfully built 754ab894cdb8
Successfully tagged mycentos:0.1
# 查看构建成功的镜像
[root@k8s-master dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 0.1 754ab894cdb8 3 minutes ago 295MB
测试运行
## 这是构建之前的官方centos镜像
[root@k8s-master dockerfile]# docker run -it centos
[root@5a792ccff9b2 /]# pwd #工作目录默认根目录
/
[root@5a792ccff9b2 /]# vim #没有vim命令
bash: vim: command not found
[root@5a792ccff9b2 /]# ifconfig #没有ifconfig命令
bash: ifconfig: command not found
## 这是通过dockerfile构建完成的镜像mycentos:0.1
[root@k8s-master dockerfile]# docker run -it mycentos:0.1
[root@8ebed8ffcb20 local]# pwd ##工作目录修改为/usr/local
/usr/local
[root@8ebed8ffcb20 local]# which vim #有vim命令
/usr/bin/vim
[root@8ebed8ffcb20 local]# which ifconfig #有ifconfig命令
/usr/sbin/ifconfig
查看镜像的构建历史记录
通过此方法,可以在拿到一个镜像时,研究一下是怎么做到的
5. RUN 执行命令
是否可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?
- Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。
- 每个指令新建一层这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常犯的一个错误。
- Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。
- 一些下载 创建 删除的命令没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是仅仅使用一个 RUN 指令,并使用
&&
将各个所需命令串联起来,简化为1层。 - 在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写 Shell 脚本,而是在定义每一层该如何构建。
- 最后建议添加清理的命令,删除为了编译构建所需要的各种软件,清理所有下载、展开的文件,缓存文件。这是很重要的一步,镜像是多层存储,每一层的东西并不会在下一层被删除,会一直跟随着镜像。因此镜像构建时,一定要确保每一层只添加真正需要添加的东西,任何无关的东西都应该清理掉。制作出了很臃肿的镜像的原因之一,就是忘记了每一层构建的最后一定要清理掉无关文件。
6. CMD 和 ENTRYPOINT 区别
CMD #设置容器启动时执行的操作(只有最后一个会生效,可被替代)
ENTRYPOINT #设置容器启动时执行的操作(可以追加命令)
测试 CMD
# 编写一个简单的CMD的dockerfile文件
[root@k8s-master dockerfile]# cat dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]
# 进行构建镜像
[root@k8s-master dockerfile]# docker build -f dockerfile-cmd-test -t cmdtest .
....
Successfully built 0a29d7f31b12
Successfully tagged cmdtest:latest
# 运行一个CMD镜像的容器,可以看到,直接输出dockerfile中写的CMD指令
[root@k8s-master dockerfile]# docker run cmdtest
.
..
.dockerenv
bin
dev
etc
home
...
# 再次运行容器,最近一个命令"-l" [ls -al]
[root@k8s-master dockerfile]# docker run cmdtest -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.
## CMD的清理向下"-l"替换了CMD ["ls","-a"]命令, "-l"不是命令所以会报错
[root@k8s-master dockerfile]# docker run cmdtest ls -al
total 0
drwxr-xr-x. 1 root root 6 Jun 23 09:41 .
drwxr-xr-x. 1 root root 6 Jun 23 09:41 ..
-rwxr-xr-x. 1 root root 0 Jun 23 09:41 .dockerenv
lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Jun 23 09:41 dev
drwxr-xr-x. 1 root root 66 Jun 23 09:41 etc
drwxr-xr-x. 2 root root 6 May 11 2019 home
....
测试 ENTRYPOINT
# 编写一个ENTRYPOINT的dockerfile文件
[root@k8s-master dockerfile]# cat dockerfile-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]
# 进行构建镜像
[root@k8s-master dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint .
....
Successfully built 120ba8d637f5
Successfully tagged entrypoint:latest
# 运行一个ENTRYPOINT镜像的容器,发现和CMD没有区别
[root@k8s-master dockerfile]# docker run entrypoint
.
..
.dockerenv
bin
dev
etc
home
....
# 再次运行容器,追加一个参数 "-l";会发现直接就输出了详细信息
# 追加的命令,是直接拼接在 ENTRYPOINT 命令的后面,而不会去替换命令
[root@k8s-master dockerfile]# docker run entrypoint -l
total 0
drwxr-xr-x. 1 root root 6 Jun 23 09:48 .
drwxr-xr-x. 1 root root 6 Jun 23 09:48 ..
-rwxr-xr-x. 1 root root 0 Jun 23 09:48 .dockerenv
lrwxrwxrwx. 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Jun 23 09:48 dev
drwxr-xr-x. 1 root root 66 Jun 23 09:48 etc
drwxr-xr-x. 2 root root 6 May 11 2019 home
....
Dockerfile中很多命令都十分的相似,我们需要了解他们的区别,最好的学习方法就是对比它们。
7. 测试 Tomcat镜像(ADD COPY)
1. 准备镜像文件,tomcat压缩包,jdk的压缩包
2. 编写dockerfile文件
建议官方命名 Dockerfile
;build
时就不需要-f
指定了
[root@k8s-master tomcat]# cat Dockerfile
FROM centos
MAINTAINER lichenxing<245684979@qq.com>
COPY readme.txt /usr/local/readme.txt
ADD jdk-8u60-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.0.27.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_60
ENV CLASSPATH $JAVA\_HOME/lib/dt.jar:$JAVA\_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.0.27
ENV CATALINA_BASH /usr/local/apache-tomcat-8.0.27
ENV PATH $PATH:$JAVA\_HOME/bin:$CATALINA\_HOME/lib:$CATALINA\_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-8.0.27/bin/startup.sh && tail -F /url/local/apache-tomcat-8.0.27/bin/logs/catalina.out
3. 构建镜像
[root@k8s-master tomcat]# pwd
/home/dockerfile/build/tomcat
[root@k8s-master tomcat]# docker build -t diytomcat ./
....
Successfully built e256e862f380
Successfully tagged diytomcat:latest
4. 运行此镜像的容器
# 将webapps目录下的一些日志或者代码可以挂载到宿主机的目录下
[root@k8s-master tomcat]# docker run -d -p 9090:8080 --name lcxtomcat -v /home/dockerfile/build/tomcat/test:/usr/local/apache-tomcat-8.0.27/webapps/test -v /home/dockerfile/build/tomcat/tomcatlogs:/usr/local/apache-tomcat-8.0.27/logs/ diytomcat
f1c38b290af2d88ca5ccfc99b5baaea77cc43d9de6a8ce75d6443125f74d2c3a
# 可以看到挂载到宿主机的目录已经同步
[root@k8s-master tomcat]# pwd
/home/dockerfile/build/tomcat
[root@k8s-master tomcat]# ls
apache-tomcat-8.0.27.tar.gz Dockerfile jdk-8u60-linux-x64.tar.gz readme.txt test tomcatlogs
[root@k8s-master tomcat]# ll tomcatlogs/
total 20
-rw-r--r--. 1 root root 6539 Jun 24 17:41 catalina.2020-06-24.log
-rw-r--r--. 1 root root 6539 Jun 24 17:41 catalina.out
-rw-r--r--. 1 root root 0 Jun 24 17:41 host-manager.2020-06-24.log
-rw-r--r--. 1 root root 280 Jun 24 17:41 localhost.2020-06-24.log
-rw-r--r--. 1 root root 0 Jun 24 17:41 localhost_access_log.2020-06-24.txt
-rw-r--r--. 1 root root 0 Jun 24 17:41 manager.2020-06-24.log
5. 进入tomcat容器中查看
[root@k8s-master tomcat]# docker exec -it lichenxingtomcat /bin/bash
[root@f1c38b290af2 local]# pwd
/usr/local
[root@f1c38b290af2 local]# ls
apache-tomcat-8.0.27 etc include lib libexec sbin src
bin games jdk1.8.0_60 lib64 readme.txt share
[root@f1c38b290af2 local]# ls -l apache-tomcat-8.0.27/
total 92
-rw-r--r--. 1 root root 57011 Sep 28 2015 LICENSE
-rw-r--r--. 1 root root 1444 Sep 28 2015 NOTICE
-rw-r--r--. 1 root root 6741 Sep 28 2015 RELEASE-NOTES
-rw-r--r--. 1 root root 16204 Sep 28 2015 RUNNING.txt
drwxr-xr-x. 2 root root 4096 Sep 28 2015 bin
drwxr-xr-x. 1 root root 22 Jun 24 09:41 conf
drwxr-xr-x. 2 root root 4096 Sep 28 2015 lib
drwxr-xr-x. 2 root root 197 Jun 24 09:41 logs
drwxr-xr-x. 2 root root 30 Sep 28 2015 temp
drwxr-xr-x. 1 root root 18 Jun 24 09:41 webapps
drwxr-xr-x. 1 root root 22 Jun 24 09:41 work
[root@f1c38b290af2 local]# ls -l apache-tomcat-8.0.27/webapps/
total 8
drwxr-xr-x. 3 root root 4096 Sep 28 2015 ROOT
drwxr-xr-x. 14 root root 4096 Sep 28 2015 docs
drwxr-xr-x. 6 root root 83 Sep 28 2015 examples
drwxr-xr-x. 5 root root 87 Sep 28 2015 host-manager
drwxr-xr-x. 5 root root 103 Sep 28 2015 manager
drwxr-xr-x. 2 root root 6 Jun 24 09:41 test
[root@f1c38b290af2 local]# ls -l apache-tomcat-8.0.27/logs/
total 20
-rw-r--r--. 1 root root 6539 Jun 24 09:41 catalina.2020-06-24.log
-rw-r--r--. 1 root root 6539 Jun 24 09:41 catalina.out
-rw-r--r--. 1 root root 0 Jun 24 09:41 host-manager.2020-06-24.log
-rw-r--r--. 1 root root 280 Jun 24 09:41 localhost.2020-06-24.log
-rw-r--r--. 1 root root 0 Jun 24 09:41 localhost_access_log.2020-06-24.txt
-rw-r--r--. 1 root root 0 Jun 24 09:41 manager.2020-06-24.log
# 测试连接性
[root@f1c38b290af2 local]# curl -I 127.0.0.1:8080
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 24 Jun 2020 09:48:16 GMT
宿主机的9090端口
6. 上传一个web站点的压缩包到test目录下进行测试
[root@k8s-master tomcat]# pwd
/home/dockerfile/build/tomcat
[root@k8s-master tomcat]# cd ./test/
[root@k8s-master test]# ll
total 20316
-rw-r--r--. 1 root root 20797013 Jun 24 18:02 jpress-web-newest.war
drwxr-xr-x. 3 root root 38 Sep 19 2016 META-INF
-rw-r--r--. 1 root root 96 Jul 27 2016 robots.txt
drwxr-xr-x. 11 root root 139 Sep 19 2016 static
drwxr-xr-x. 4 root root 31 Sep 19 2016 templates
drwxr-xr-x. 6 root root 75 Jun 24 18:02 WEB-INF
先不用做安装,只测试。没有数据库环境
- 在主机的test目录下就可以修改代码文件。
# 可以在宿主机上直接查看访问的日志文件
[root@k8s-master tomcat]# tail -f tomcatlogs/catalina.out
JFinal action report -------- 2020-06-24 10:05:59 ------------------------------
Controller : io.jpress.install.InstallController.(InstallController.java:1)
Method : step2
Interceptor : io.jpress.core.interceptor.JI18nInterceptor.(JI18nInterceptor.java:1)
io.jpress.interceptor.GlobelInterceptor.(GlobelInterceptor.java:1)
io.jpress.interceptor.AdminInterceptor.(AdminInterceptor.java:1)
io.jpress.core.interceptor.HookInterceptor.(HookInterceptor.java:1)
io.jpress.install.InstallInterceptor.(InstallInterceptor.java:1)
--------------------------------------------------------------------------------
8. 发布镜像到DockerHub
官方DockerHub仓库
https://hub.docker.com/
需要注册自己的账户,确认可以登录
在服务器上提交镜像到官方仓库
[root@k8s-master tomcat]# docker login -u 245684979
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
# 为封装好的镜像打一个标签
# 这里要注意 给自己镜像命名的时候格式应该是: docker注册用户名/镜像名,不然是push不上去的
[root@k8s-master tomcat]# docker tag diytomcat:latest 245684979/diytomcat:1.0
[root@k8s-master tomcat]# docker push 245684979/diytomcat:1.0
The push refers to repository [docker.io/245684979/diytomcat]
0877995fc452: Pushing 9.192MB/57.19MB
5dedcbd44b60: Pushing 2.864MB/12.94MB
f675325f4324: Pushing 1.607MB/364.8MB
c966da79fa06: Pushing 2.56kB
eb29745b8228: Pushing 6.019MB/215.3MB
...
提交的时候也是按照镜像的层级来进行提交的,提交成功后在DockerHub就可以看到了
9. 发布镜像到阿里云镜像仓库
登陆阿里云
找到容器镜像服务
创建命名空间
创建容器镜像
浏览操作指南
[root@k8s-master ~]# docker push registry.cn-beijing.aliyuncs.com/lichenxing/lcxtomcat:1.0
The push refers to repository [registry.cn-beijing.aliyuncs.com/lichenxing/lcxtomcat]
0877995fc452: Pushed
5dedcbd44b60: Pushed
f675325f4324: Pushed
c966da79fa06: Pushed
eb29745b8228: Pushed
1.0: digest: sha256:2e3c25e752897e3c166cc3b372bddefb3de5db0fb04d1f8a883580e04bdd6c90 size: 1372
10. 发布镜像到私有仓库
有时候使用 Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。docker-registry
是官方提供的工具,可以用于构建私有的镜像仓库。
普通的registry
默认情况下,仓库会被创建在容器的/var/lib/registry
目录下。可以通过 -v 参数来将镜像文件存放在本地的指定路径。
# 运行官方registry镜像
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry
# 将镜像加速器地址改为本地
[root@k8s-master ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["192.168.0.10:5000"]
}
systemctl restart docker
# 给镜像打标签
docker tag diytomcat 192.168.0.10:5000/lcxtomcat:1.0
# 上传镜像到私有仓库
[root@k8s-master ~]# docker push 192.168.0.10:5000/lcxtomcat
The push refers to repository [192.168.0.10:5000/lcxtomcat]
0877995fc452: Pushed
5dedcbd44b60: Pushed
f675325f4324: Pushed
c966da79fa06: Pushed
eb29745b8228: Pushed
1.0: digest: sha256:2e3c25e752897e3c166cc3b372bddefb3de5db0fb04d1f8a883580e04bdd6c90 size: 1372
# 查看私有仓库上传的镜像
[root@k8s-master ~]# curl 127.0.0.1:5000/v2/\_catalog
{"repositories":["lcxtomcat"]}
十、企业级镜像仓库 Harbor
https://github.com/goharbor/harbor/tree/release-2.0.0
Habor是由VMWare公司开源的容器镜像仓库。事实上,Habor是在Docker Registry上进行了相应的 企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面,基于角色的访 问控制 ,AD/LDAP集成以及审计日志等,足以满足基本企业需求。
下载地址:https://github.com/goharbor/harbor/releases
软件版本
- 在Linux主机上: docker 17.06.0-ce +和docker-compose 1.18.0+
1. 安装
#安装docker compose
yum install -y docker-compose
docker-compose --version
docker-compose version 1.18.0, build 8dd22a9
#这里使用1.9版本的harbor
tar xf harbor-offline-installer-v1.9.1.tgz -C /opt/
cd /opt/harbor/
# 修改配置文件
vim harbor.yml
hostname: 192.168.0.10
harbor_admin_password: 123456
#执行prepare脚本
./prepare
#执行脚本
sh install.sh
[Step 0]: checking installation environment ...
Note: docker version: 19.03.11
Note: docker-compose version: 1.18.0
[Step 1]: loading Harbor images ...
2. 访问
admin 123456
3. 推送镜像
docker tag nginx:1.18.0 192.168.0.10/library/nginx:1.18.0
#修改daemon.json配置文件,指定仓库IP为192.168.0.10
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["192.168.0.10"]
}
systemctl restart docker
docker-compose up -d
4. 添加新用户
#登陆普通用户guest
[root@k8s-master harbor]# docker login 192.168.0.10
Username: guest
Password: #Lcx123456
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
推送镜像
#推送其他镜像到harbor
##nginx
[root@k8s-master harbor]# docker push 192.168.0.10/library/nginx:1.18.0
The push refers to repository [192.168.0.10/library/nginx]
97d4365452ad: Pushed
d1c9311342b8: Pushed
edf3aa290fb3: Pushed
1.18.0: digest: sha256:15b2135c75230e8282f9c3039fd50f22e90929eafc827f6b8d629bbe190c33d0 size: 952
## php
docker tag php:v2 192.168.0.10/library/php:v2
docker push 192.168.0.10/library/php:v2
## tomcat
docker tag tomcat:v2 192.168.0.10/library/tomcat:v2
docker push 192.168.0.10/library/tomcat:v2
## mysql
docker tag mysql:5.7 192.168.0.10/library/mysql:5.7
docker push 192.168.0.10/library/mysql:5.7
5. 创建私有项目project
#登出
docker logout
>/root/.docker/config.json
#登陆admin用户
WARNING: Error loading config file: /root/.docker/config.json: EOF
Username: admin
Password: #123456
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
#上传一个镜像
docker tag tomcat:v2 192.168.0.10/project/tomcat:v2
docker push 192.168.0.10/project/tomcat:v2
十一、Docker网络
- None:不为容器配置任何网络功能,–net=none
- Container:与另一个运行中的容器共享Network Namespace,–net=container:containerID(K8S)
- Host:与宿主机共享Network Namespace,–network=host 性能最高
- Bridge:Docker设计的NAT网络模型(默认)
# 清除所有容器和镜像环境
docker rm -f $(docker ps -aq)
docker rmi `docker images -qa`
# 启动一台容器
[root@k8s-master ~]# docker run -d -P --name tomcat01 tomcat
# 查看容器的网卡信息
[root@k8s-master ~]# docker exec -it tomcat01 ip a
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
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# linux宿主机可以ping通容器内部
[root@k8s-master ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp\_seq=1 ttl=64 time=0.060 ms
64 bytes from 172.17.0.2: icmp\_seq=2 ttl=64 time=0.053 ms
原理:
- 每启动一个docker容器,docker都会给容器分配一个ip,我们只要按照了docker,就会有一个网卡docker0,Bridge桥接模式使用的技术是
evth-pair
技术。 - evth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连,正因为有这个特性,evth-pair充当一个桥梁,专门连接各种虚拟网络设备。每开启运行一个容器,就会增加一对儿对应的网卡。
- Openstack、Docker、OVS都是使用的 evth-pair技术。
- 容器删除,对应的网桥也被删除
1. Bridge模式
当Docker
进程启动时,会在主机上创建一个名为docker0
的虚拟网桥,此主机上启动的Docker
容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0
子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair
设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0
(容器的网卡),另一端放在主机中,以vethxxx
这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show
命令查看。
bridge
模式是 docker 的默认网络模式,不写–net
参数,就是bridge
模式。使用docker run -p
时,docker 实际是在iptables
做了DNAT
规则,实现端口转发功能。可以使用iptables -t nat -vnL
查看。
–link 容器互联
随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数。
思考:编写一个微服务,database url=ip:,项目不重启,数据库ip换掉了,我们希望可以处理这个问题,可以用名字来进行访问容器吗?
# 创建俩台容器 tomcat01和tomcat02
docker run -it -d -P --name tomcat01 245684979/diytomcat:1.0
docker run -it -d -P --name tomcat02 245684979/diytomcat:1.0
# 尝试相互ping不能ping通
[root@k8s-master ~]# docker exec -it tomcat02 ping tomcat01
ping: tomcat01: Name or service not known
# 创建tomcat03容器,使用--link,即可解决了网络连通问题
docker run -it -d -P --name tomcat03 --link tomcat02 245684979/diytomcat:1.0
# 通过容器tomcat03来ping容器tomcat02可以ping通了
[root@k8s-master ~]# docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp\_seq=1 ttl=64 time=0.055 ms
# 反向是不可以ping通 02 ping 03
[root@k8s-master ~]# docker exec -it tomcat02 ping tomcat03
ping: tomcat03: Name or service not known
查看网络的信息
# 查看网络详细信息
[root@k8s-master ~]# docker network inspect cd3809ba6584
[
{
"Name": "bridge",
"Id": "cd3809ba6584494c86e9802d3dfc6424bb33226c93b80bd31d9f43dd25c200c2",
"Created": "2020-06-29T11:20:18.826585474+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"07926c954f2ad324dc977bed26af4953713355dcc5b67aea97f18830984bfce5": {
"Name": "tomcat02",
"EndpointID": "ff5fc39a60e1c6291afed28de6c2d14a5c43554e9a6dbff04495ee4d4ae0ec64",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16", # 为tomcat02分配的IP
"IPv6Address": ""
},
"b423584cb2f658703f42bfc8fe9fe40e61b3b9b7d29d4bee5af213340e9058ae": {
"Name": "tomcat01",
"EndpointID": "2e6d7bf8db206b2392eec7b959c5c695e61e1826e1eb03f3e8d0d012b3a3cc63",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16", # 为tomcat01分配的IP
"IPv6Address": ""
},
"b820e4afdccdb8a50045c77de6e575bff0df692ed144673e2cb2bb2259a76c08": {
"Name": "tomcat03",
"EndpointID": "d7bf4b2f4b213f6497cfcfdac40c827d104f56dee5a6cd14fade2b48d8ae9f54",
"MacAddress": "02:42:ac:11:00:04",
"IPv4Address": "172.17.0.4/16", # 为tomcat03分配的IP
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default\_bridge": "true",
"com.docker.network.bridge.enable\_icc": "true",
"com.docker.network.bridge.enable\_ip\_masquerade": "true",
"com.docker.network.bridge.host\_binding\_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
# 查看tomcat03的信息,可以看到links指定的是tomcat02
[root@k8s-master ~]# docker inspect tomcat03
....
"Links": [
"/tomcat02:/tomcat03/tomcat02"
],
....
# 通过查看tomcat03的hosts文件也可以看到
[root@k8s-master ~]# docker exec -it tomcat03 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 07926c954f2a # 指定了tomcat02
172.17.0.4 b820e4afdccd
--link
就是在hosts配置中增加了一个主机名的解析- 随着 Docker 网络的完善,建议将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数
- docker0问题 不支持容器名连接访问。
自定义网络
查看网络
# 查看网络
[root@k8s-master ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
cd3809ba6584 bridge bridge local
018532904f4e host host local
edfe5b0c21a1 none null local
# 清除测试的所有容器
docker rm -f $(docker ps -aq)
# 创建一台容器; --network brigde 就是docker0
docker run -d -P --name tomcat01 --network bridge tomcat
# 创建一个网络mynet
# --driver : 网络模式
# --subnet : 子网地址
# --gateway : 子网的网关地址
docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet
# 查看自己创建的网络详细信息
[root@k8s-master ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "ea720ae53f20b83193bca0c1dbb6296165539aa4c547f1ef37028e705b87da6c",
"Created": "2020-06-29T14:33:22.194817791+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16", #子网
"Gateway": "172.20.0.1" #网关
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
启动两台容器;指定创建的自定义网络
docker run -d -P --name tomcat-net01 --net mynet tomcat
docker run -d -P --name tomcat-net02 --net mynet tomcat
# 再次查看网络详情,可以看到启动的容器的IP
[root@k8s-master ~]# docker network inspect mynet
....
"Containers": {
"2767e468d20157e43b67174eeef94267ce2b3a5b9f66446b24fd17c06549fdb3": {
"Name": "tomcat-net01",
"EndpointID": "abadd831f2591a0d2aed089abac60292cfc0925193d6f3394131955140118750",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
},
"4a70bba89baf3e98b4f3e35de9ee19d5363f06c592dff2bf81134fbc187ac0a0": {
"Name": "tomcat-net02",
"EndpointID": "8cdf9df77303ec7c3562e4b216d09ac5c5a39a7d7a5a1563b93ea7f5fd4d5060",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
}
},
# 再次测试ping连接; ping主机名也可以ping通了
[root@k8s-master ~]# docker exec -it tomcat-net01 ping 172.20.0.3
PING 172.20.0.3 (172.20.0.3) 56(84) bytes of data.
64 bytes from 172.20.0.3: icmp\_seq=1 ttl=64 time=0.111 ms
[root@k8s-master ~]# docker exec -it tomcat-net01 ping tomcat-net02
PING tomcat-net02 (172.20.0.3) 56(84) bytes of data.
64 bytes from tomcat-net02.mynet (172.20.0.3): icmp\_seq=1 ttl=64 time=0.042 ms
--------------------------------------
##现在不使用--link也可以ping通主机名了
自定义的网络docker都已经帮我们维护好了对应的关系,平时也推荐这样使用网络。
优势:
- Redis:不同的集群使用不同的网络,保证集群是安全和健康的
- MySQL:不同的集群使用不同的网络,保证集群是安全和健康的
2. Host 模式
如果启动容器的时候使用host
模式,那么这个容器将不会获得一个独立的Network Namespace
,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
# 运行一个host网络的容器
docker run -it -d -P --name tomcat-host01 --net host tomcat
# 查看此容器的ip地址和宿主机一致
[root@k8s-master ~]# docker exec -it tomcat-host01 ip a
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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:8a:1a:eb brd ff:ff:ff:ff:ff:ff
inet 192.168.0.10/24 brd 192.168.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe8a:1aeb/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:8a:1a:f5 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.10/24 brd 172.16.0.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe8a:1af5/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:8d:a8:1d:4b 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:8dff:fea8:1d4b/64 scope link
valid_lft forever preferred_lft forever
21: br-45945e527658: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:16:06:bd:c9 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.1/16 brd 172.20.255.255 scope global br-45945e527658
valid_lft forever preferred_lft forever
inet6 fe80::42:16ff:fe06:bdc9/64 scope link
valid_lft forever preferred_lft forever
3. Container 模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
# 运行一个centos镜像容器
[root@k8s-master ~]# docker run -it -d --name centos01 centos
[root@k8s-master ~]# docker exec -it centos01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
# 运行一个Container模式的容器; 指定centos01容器;查看网络
[root@k8s-master ~]# docker run -it -d --name centos-container --network container:centos01 centos
[root@k8s-master ~]# docker exec -it centos-container ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
4. None模式
使用none
模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。
# 运行一个none模式的容器
docker run -it -d --name centos-none --network none centos
# 进入容器查看网卡发现没有ip地址
[root@k8s-master ~]# docker exec -it centos-none ip a
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
5. 网络连通
# 用bridge模式的容器去ping自定义网络的容器;发现ping不通,因为网络不同
[root@k8s-master ~]# docker exec -it tomcat01 ping tomcat-net01
ping: tomcat-net01: Name or service not known
测试 将默认 bridge 模式的容器 tomcat01 和 自定义 mynet 网络打通
docker network connect mynet tomcat01
# 查看mynet网络详情
docker network inspect mynet
# 一个容器 两个ip地址!
[root@k8s-master ~]# docker exec -it tomcat01 ip a
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
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
40: eth1@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:14:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.20.0.4/16 brd 172.20.255.255 scope global eth1
valid_lft forever preferred_lft forever
# 可以ping通了
[root@k8s-master ~]# docker exec -it tomcat01 ping tomcat-net01
PING tomcat-net01 (172.20.0.2) 56(84) bytes of data.
64 bytes from tomcat-net01.mynet (172.20.0.2): icmp\_seq=1 ttl=64 time=0.045 ms
# 而其他的是依旧ping不通的
[root@k8s-master ~]# docker exec -it tomcat02 ping tomcat-net01
ping: tomcat-net01: Name or service not known
总结:如果要跨网络操作其他容器,就需要使用
docker network connect
连通。
6. 部署一个Redis集群
# 创建一个redis网络
docker network create redis --subnet 172.30.0.0/16
# 执行一下命令创建6套redis目录和配置文件
for port in $(seq 1 6);\
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done
[root@k8s-master ~]# tree /mydata/redis/
/mydata/redis/
├── node-1
│ └── conf
│ └── redis.conf
├── node-2
│ └── conf
│ └── redis.conf
├── node-3
│ └── conf
│ └── redis.conf
├── node-4
│ └── conf
│ └── redis.conf
├── node-5
│ └── conf
│ └── redis.conf
└── node-6
└── conf
└── redis.conf
# 依次启动6台redis容器
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.30.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
资料预览
给大家整理的视频资料:
给大家整理的电子书资料:
如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
│ └── conf
│ └── redis.conf
├── node-4
│ └── conf
│ └── redis.conf
├── node-5
│ └── conf
│ └── redis.conf
└── node-6
└── conf
└── redis.conf
依次启动6台redis容器
docker run -p 6371:6379 -p 16371:16379 --name redis-1
-v /mydata/redis/node-1/data:/data
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.30.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2
-v /mydata/redis/node-2/data:/data
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.30.0.12 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3
-v /mydata/redis/node-3/data:/data
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.30.0.13 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6374:6379 -p 16374:16379 --name redis-4
-v /mydata/redis/node-4/data:/data
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.30.0.14 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6375:6379 -p 16375:16379 --name redis-5
-v /mydata/redis/node-5/data:/data
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.30.0.15 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6
-v /mydata/redis/node-6/data:/data
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf
-d --net redis --ip 172.30.0.16 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf
### 最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
### 资料预览
给大家整理的视频资料:
[外链图片转存中...(img-R98lgUTQ-1715505441982)]
给大家整理的电子书资料:
[外链图片转存中...(img-A2GKKAmj-1715505441983)]
**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**