Docker学习笔记

docker:解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术

Docker本身是一个容器运行载体或称之为管理引擎。我们把引用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例(类似Java中new出来的一个对象).

image文件可以看作是容器的模板,Docker根据image文件生成容器的实例,同一个image文件,可以生成多个同时运行的容器实例。

比较Docker和传统虚拟化方式的不同之处:

1.传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需要应用进程;

2.容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便;

3.每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源

Docker三要素:镜像,容器,仓库

镜像文件:image文件生成的容器实例,本身也是一个文件,称为镜像文件

容器实例:一个容器运行一种服务,当我们需要的时候,就可以通过docker客户端创建一个对应的运行实例,也就是我们的容器。

仓库:就是防一堆镜像的地方,我们可以把镜像发布到仓库中,需要的时候再从仓库中拉下来就可以了

一、

Docker安装

Install Docker Engine on CentOS | Docker Documentation

1.

 yum install -y yum-utils

2.设置stable镜像仓库

yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

 3.更新yum软件包索引

yum makecache fast

4.安装docker引擎

 yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

5.启动docker

systemctl start docker

 6.helloworld

docker run hello-world

安装成功: 

 (1)卸载docker

yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin

rm -rf /var/lib/docker
rm -rf/var/lib/containerd

 (2)停止docker服务

systemctl stop docker

二、阿里云镜像加速器

注册阿里云开放云原生应用-云原生(Cloud Native)-云原生介绍 - 阿里云

控制台->弹性 计算

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://n3twaq8i.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

 三.Docker常用命令

1.帮助启动类命令:

  1. 启动docker: systemctl start docker
  2. 停止docker: systemctl stop docker
  3. 重启docker: systemctl restart docker
  4. 查看docker状态:systemctl status docker
  5. 开机启动:systemctl enable docker
  6. 查看docker概要信息:docker info 
  7. 查看docker总体帮助文档:docker --help
  8. 查看docker命令帮助文档:docker 具体命令 --help

2.镜像命令

  1. 列出本地主机上的镜像:docker images    (-a:列出本地所有镜像;-q:只显示镜像ID)

         (1)REPOSITORY:表示镜像的仓库源

       (2)TAG:镜像的标签版本号

         (3)IMAGE ID :镜像ID

         (4):CREATED:镜像创建时间

        (5)SIZE:镜像大小

 2. 查询远程仓库镜像:docker search 镜像名字  (-limit :只列出N个镜像。默认25个)

3.下载镜像:docker pull 镜像名字 [:tag] (版本号,默认最新版本)

4.查看镜像/容器/数据卷所占的空间:docker system df 

5.删除镜像:docker rmi 镜像名字

        删除单个:docekr rmi -f 镜像ID

        删除多个:docker rmi -f 镜像名1:TAG 镜像名2:TAG

        删除全部:docker rmi -f $(docker images -qa)

谈谈docker虚悬镜像是什么?

仓库名,标签都是<none>的镜像,俗称虚悬镜dangling image

3.容器命令

        OPTIONS:

                (1)   --name="容器新名字" :为容器指定一个名称

                (2)   -d :后台运行容器并返回容器ID,也即启动守护容器;

              (3) -i : 以交互模式运行容器。通常与 -t 同时使用;

              (4)-t : 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

                        也即是启动交互式容器(前端有伪终端,等待交互);

              (5)-P : 随机端口映射,大写P;

                (6)  -p : 指定端口映射,小写p;

 启动交互式容器(前台命令行):

解决:

[root@localhost root123]# docker run -it ubuntu /bin/bash
WARNING: IPv4 forwarding is disabled. Networking will not work.

2.列出当前正在运行的容器:docker ps [OPTIONS]

OPTIONS:

        (1) -a : 列出当前所有正在运行的容器 + 历史上运行过的

        (2) -l : 显示最近创建的容器

        (3) -n : 显示最近n个创建的容器

        (4) -q : 静默模式,只显示容器编号

3.退出容器:

(1)exit : run进去容器,exit退出,容器停止;

(2)ctrl+p+q :run进去容器,ctrl+p+q退出,容器不停止;

 4.启动已经停止运行的容器:docker start 容器ID或容器名

 5.重启容器:docker restart 容器ID或容器名

 6.停止容器:docker stop 容器Id或容器名

 7.强制停止容器:docker kill 容器ID或容器名

 8.删除已经停止的容器:docker rm 容器ID ;docker rmi 镜像 

        -f: 强制删除  

        一次性删除多个容器实例:慎用!!!

                (1):docker rm -f $(docker ps -a -q)

                (2):docker ps -a -q | xargs docker rm

-d的讲解:

        #使用镜像centos:latest 以后台模式启动一个容器        docker run -d centos

问题:然后docker ps -a 进行查看,会发现容器已经退出

        很重要的要说明一点:docker容器后台运行,就必须有一个前台进程

容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出。

这是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可,例如service nginx start ,但是,这样做nginx为后台进程模式运行,就导致docker前台没有运行的应用,这样的容器后台启动后,就会自杀因为他觉得他没有事可做,所以,最佳的解决方案式是,将你要运行的程序以前台进程的形式运行,常见就是命令行模式,表示我还有工作,别中端

运行redis 6.0.8

  1. 前台运行redis :docker run -it redis:6.0.8
  2. 后台运行redis:docker run -d reids:6.0.8
  3. 查看日志:docker logs 容器ID 
  4. 查看容器内运行的进程:docker top 容器ID
  5. 查看容器内部细节:docker inspect 容器ID
  6. 进入正在运行的容器:
    1. docker exec -it 容器ID bashShell
    2. 重新进入:  docker attach 容器ID
    3. 上述两个区别:
      1. attach 直接进入容器启动命令的终端,不会启动新的进程。用exit退出,会导致容器的停止;
      2. exec是在容器中打开新的终端,并且可以启动新的进程。用exit退出,不会导致容器的停止。
      3. 推荐使用docker exec 命令,因为退出容器终端,不会导致容器的停止。

7.从容器内拷贝文件到主机:docker cp 容器ID:容器内路径   目的主机路径

8.导入和导出容器:

        (1)export 导出容器的内容留作为一个tar归档文件(对应import命令)

        (2)import 从tar 包中的内容创建一个新的文件系统在导入为镜像

        案例:

                (1)docker export 容器ID > 文件名.tar

                (2)cat 文件名.tar | docker import -镜像用户/镜像名:镜像版本号

四、Docker镜像

1.什么是镜像:

        是一种轻量级,可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个 可交付的运行环境(包括代码,运行时需要的库,环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。

2.UnionFS(联合文件系统):

        Union文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交 一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于继承镜像,可以制作各种具体的应用镜像

3.Docker镜像加载原理:

        docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

        bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件bootfs。这一层与我们典型的Linux和Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核。此时系统也会卸载bootfs。

        rootfs,在bootfs之上,包含的就是典型的Linux系统中的/dev,/proc/bin/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等待。

        对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的keernel,自己只需要提供rootfs就行了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版本可以公用bootfs。

4.为什么Docker镜像采用这种分层结构呢

        镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。

        比如说有多个镜像都从相同的base镜像构建而来,那么Docker Host只需要在磁盘上保存一份base镜像;同时内存也只需要加载一份base镜像,就可以为所有容器服务了,而且镜像的每一层都可以被共享。

Docker镜像层都只是只读的,容器层是可写的;当容器启动时,一个新的可写容器被加载到镜像的顶部,这层通常被称作 ”容器层“,容器层之下的都叫”镜像层“;所有对容器的改动-无论添加删除,还是修改文件都只发生在容器层,只有容器层是可写的,容器层下面的所有镜像层都是只读的。

 5.docker 的commit 案例 提交生成一个新的镜像

        docker commit 提交容器副本使之成为一个新的镜像

        docker commit -m="提交的描述信息" -a=”作者“容器ID要创建的目标镜像名:[标签号]

案例演示ubuntu安装vim

       1)apt-get update
        2)apt-get -y install vim

 五.本地镜像发布到阿里云

1.进入阿里云>控制台>弹性镜像容器服务>个人

2.创建镜像仓库>本地仓库>进入管理界面获得脚本

 3.将镜像推送到阿里云registry 

$ docker login --username=aliyun4214424794 registry.cn-hangzhou.aliyuncs.com$ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/sutdy_docker/myubuntu1.3:[镜像版本号]$ docker push registry.cn-hangzhou.aliyuncs.com/sutdy_docker/myubuntu1.3:[镜像版本号]

 4.将阿里云的镜像拉取到本地

六.本地镜像发布到私有库

 1.下载镜像Docker Registry : docker pull registry

2.运行私有库有Registry ,相当于本地有个私有Docker hub :

docker run -d -p 5000:5000 -v/zcl/myregistry/:/tmp/registry --privileged=true registry

3.ubuntu安装ifconfig功能

        (1) apt-get update

        (2)apt-get install net-tools
        (3)安装完成后,commit我们的新镜像:

                        docker commit -m="ifconfig cmd add" -a="zcl" 6ae9dccbc190 zclubuntu:1.2

4.curl验证私服库上有什么镜像: curl -XGET http://192.168.238.80:5000/v2/_catalog

5.将新镜像zclubuntu1.2修改符合规范的Tag: docker tag 镜像:TAG Host:Port/Repository:Tag 

6.修改配置文件使之支持http 

        (1) vim /etc/docker/daemon.json

        (2)配置文件中新增:别忘记”  , “

      (3)重启docker : systemctl restart docker

        (4)开启本地私服库:

                docker run -d -p 5000:5000 -v/zcl/myregistry/:/tmp/registry --privileged=true registry

 7.push推送到私服库:docker push 192.168.238.80:5000/zclubuntu:1.2

 8.curl验证私服库上有什么镜像: curl -XGET http://192.168.238.80:5000/v2/_catalog

9.pull到本地并运行: docker pull 192.168.238.80:5000/zclubuntu:1.2

七.Docker容器卷

Docker挂载主机目录访问如果出现cannot open dircctory.:Permission denied

解决方法:挂载目录后多加一个-privileged=true 参数即可

7.1.docker容器卷是什么:有点类似我们redis里面的rdb和aof文件 ;将docker容器内的数据保存进宿主机的磁盘中。

         卷就是目录或文件。存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持久化存储或共享数据的特性;

        卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷;

 运行一个带有容器卷存储功能的容器实例

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

7.2.能干什么:将运用与运行的环境打包镜像,run后形成实例运行,但是我们对数据的要求时持久化的。

        docker容器产生的数据,如果不备份,那么当容器实例删除后,容器内地数据自然就没有了。为了能保存数据在docker中我们使用卷。

        特点:        

  1. 数据卷可在容器之间共享重用数据
  2. 卷中的更改可以直接实例时生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续待没有容器使用它为止            

7.3.读写规则映射添加:

        (1)读写(默认):                          

              docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw  镜像名

         (2)只读:容器实例内部被限制,只能读取不能写:

                docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro  镜像名

7.4.卷的继承和共享 

        容器2继承容器1的卷规则:

                docker run -it --privileged=true--volumes-from父类 --name u2 ubuntu

八.Docker常规安装 

1.安装Tomcat:

        (1)Docker Hub 上面查找tomcat镜像

docker search tomcat

        (2)从docker hub 上拉取tomcat镜像到本地

docker pull tomcat

      (3)查看是否有拉取到tomcat

docker images

         (4)使用tomcat镜像创建容器实例(也叫运行镜像):

        -p小写:主机端口号:docker容器端口    ; -P大写:随机分配端口

        -i:交互    ;    t:终端    ;   -d:后台

docker run -it -p 8080:8080 tomcat

        (5)访问猫主页

                问题报404!!!

        解决:1.可能没有映射端口或者关闭防火墙

                   2. (1)进入tomcat容器中,删除webapps: rm -r webapps

                       (2)将webapps.dist 改名替换成webapps : mv webapps.dist webapps 

                 (6)免修改版:docker pull billygoo/tomcat8-jdk8

                                        docker run -d -p 8080:8080 --name mytomcat billygoo/tomcat8-jdk8

安装成功



 2.安装mysql

        简易版的运行:(存在中文乱码问题,以及数据备份问题)

        (1)Docker Hub 上面查找mysql镜像:docker search mysql

        (2)从docker hub上(阿里云加速器)拉取MySQL镜像到本地 标签为5.7 :

                 docker pull mysql:6.7

        (3)使用mysql5.7镜像创建容器(也叫运行镜像):

docker run -p 3306:3306 --name some-mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:tag

        (4)进入mysql :docker exec -it  > 进入mysql  密码:123456          (5)使用mysql

 (6)使用navicat连接mysql

 1)插入中文会报错

 2)修正字符集编码:SHOW VARIABLES LIKE 'character%'  

 实战版:解决简易版存在的问题

一.乱码

        1.

docker run -d -p 3306:3306 --privileged=true -v /zclroot/mysql/log:/var/log/mysql -v /zclroot/mysql/data:/var/lib/mysql -v /zclroot/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7

        2.新建my.conf ,通过容器卷同步给mysql容器实例,解决中文乱码问题

[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8

        3.重新启动mysql容器实例再重新进入并查看字符编码 : docker restart mysql

         乱码解决成功!!!

二.数据库被删除数据恢复

        在这已经配置了容器数据卷,当容器重新启动时,数据会从容器卷中重新读取达到数据备份的作用

 数据依旧可以读取

3.安装Redis

        (1)在centos宿主机下新建目录/app/redis: mkdir -p /app/redis

        (2)将一个redis.conf文件模板拷贝到/app/redis目录下

        (3)修改redis.conf配置

                将bind注解掉,允许redis外地连接

                

                daemonize 改为no 或注释起来,因为该配置和docker run 中 -d 参数冲突,会导致容器一直启动失败

                

         (3)启动redis镜像

docker run -p 6379:6379 --name myr3 --privileged=true -v  /app/redis/redis.conf:/etc/redis/redis.conf -v/app/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf

九.高级学习

 1.docker复杂安装

        1.mysql主从复制原理:

                (1)新建主服务器容器实例3307        

              

docker run -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

                (2)进入/mydata/mysql-master/conf目录下新建my.cnf

[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=1
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql  
## 开启二进制日志功能
log-bin=mall-mysql-bin  
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M  
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed  
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062

                (3)修改完配置后重启master实例

docker restart mysql-master

                (4)进入mysql-master容器

docker exec -it mysql-master /bin/bash
mysql -uroot -proot

                (5)master容器实例内创建数据同步用户

CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slave'@'%';

                (6)创建从服务器容器实例3308

docker run -p 3308:3306 --name mysql-slave -v /mydata/mysql-slave /log:/var/log/mysql -v /mydata/mysql-slave /data:/var/lib/mysql -v /mydata/mysql-slave /conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7

                (7)进入/mydata/mysql-slave/conf目录下新建my.cnf

[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=2
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql  
## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin  
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M  
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed  
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062  
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin  
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1  
## slave设置为只读(具有super权限的用户除外)
read_only=1

                (8)修改完配置后重启slave实例

docker restart mysql-slave

                (9)在主数据库中查看主从同步状态

show master status;

                (10)进入mysql-slave容器

docker exec -it mysql-slave /bin/bash
mysql -uroot -p

                (11)在从数据库中配置主从复制

 ·主从复制命令参数说明
master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。

change master to master_host='宿主机ip',
master_user='slave',
master_password='123456',
master_port=3307,
master_log_file='mall-mysql-bin.000001',
master_log_pos=617,
master_connect_retry=30;

                (12)在从数据库中查看主从同步状态

show slave status \G;

                 (13)在从数据库中开启主从同步

start slave;

                (14)查看从数据库状态发现已经同步

show slave status \G;

                 (15)主从复制测试:主机新建库-使用库-新建表-插入数据,

                                                        从机使用库-查看记录

                       master:

                

        slave:

        



 2.安装redis集群

面试题:1~2亿条数据需要缓存,请问如何设计这个存储案例

 回答:单机单台100%不可能,肯定是分布式存储。有三种方式

       1.哈希取余分区

               2亿条记录就是2亿个k,v,我们单机不行必须要分布式多机,假设有三台机器构成一个集群,用户每次读写操作都是根据公式hash(key)%N个机器个数,计算出哈希值,用来决定数据映射到哪一个节点上。

                优点:简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台,8台,10台,就能保证一段时间的数据支撑,使用hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求,起到负载均衡——分而治之的作用

                缺点:原来规划好的节点,进行扩容或缩容就比较麻烦,不管是扩容,每次数据变动导致节点有变化,映射关系需要重新进行计算,在服务器个数不变时没有问题,如果需要弹性扩容或故障停机的情况下,原来的取余公式就会发生变化,Hash(key)%3会变成Hash(key)%?。此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。

        某个redis机器宕机,由于台数数量发生变化,会导致hash取余全部数据重新洗牌

        2.一致性哈希算法分区

                当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系。将所有的存储节点排列在收尾相接的Hash环上,每个key在计算Hash后会顺时针找到临界的存储点存放。而当有节点加入或退出时仅影响该节点在Hash环上顺时针相邻的后续节点。三个步骤: 算法构建一致性哈希环;服务器IP节点映射;key落到服务器的落键规则   .

                优点:加入和删除节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。

                缺点:数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果。

        3.哈希槽分区(常用)

                哈希槽实质就是一个数组,数组【0~2^14-1】形成的hash slot 空间。解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽,用于管理数据和节点之间的关系。现在就相当于节点上方的就是槽,槽里面放的是数据。



三主三从redis集群扩缩容配置案例 

        1.关闭防火墙+启动docker后台服务

        2.新建6个docker容器实例   --net hsot :使用宿主机的IP和端口,默认;--privileged=true :获取宿主机root用户权限 ;--cluster-enable yes : 开启redis集群  --appendonly yes :开启持久化

docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

         3.进入容器redis-node-1并为6台机器构建集群关系

                (1)进入容器

docker exec -it redis-node-1 /bin/bash

                (2)构建主从关系  --cluster-replicas 1 :表示为每个master构建一个slave节点

redis-cli --cluster create 192.168.238.80:6381 192.168.238.80:6382 192.168.238.80:6383 192.168.238.80:6384 192.168.238.80:6385 192.168.238.80:6386 --cluster-replicas 1

        

 链接进入6381作为切入点,查看集群状态        



主从容错切换迁移案例

        数据读取存储

               · 启动6机构成的集群并通过exec进入

               · 对6381新增两个key :以单机的方式启动redis

               防止路由失效加参数-c并新增key : 加 -c :表示以集群的方式启动redis

                 

                 `检查集群信息: redis-cli --cluster check 192.168.238.80:6381

                

         容错切换迁移

                ·主6381和从机切换,先停止主机6381

                ·再次查看集群信息                  (哨兵模式:反客为主的自动版)

              ·先还原之前的3主3从 

                        1.先启动6381    docker start redis-node-1  (6381恢复后成为了6385的slaver )

                        2.再停6385   docker stop redis-node-5        

                        3.再重新启动6385 :  docker start redis-node-5 

                ·查看集群状态       

 主从扩容案例

  1.  新建6387,6388两个节点+新建后启动+查看是否有8节点
    docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
    docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
  2. 进入6387容器实例内部 :docker exec -it redis-node-7 /bin/bash
  3. 将新增的6387节点(空槽号)作为master节点加入原集群
    redis-cli --cluster add-node 192.168.238.80:6387 192.168.238.80:6381 
  4. 检查集群情况第1次  ;redis-cli --cluster check 192.168.238.80:6381
  5. 重新分配槽号:redis-cli --cluster reshard 192.168.238.80:6387
  6. 检查集群情况第2次:原来的三个master每个将自己从左边开始给了一点给6387,是的6387有4096个槽位,并不是重新分配
  7. 为主节点6387分配从节点6388:redis-cli --cluster add-node ip:新slaver端口 ip:新master端口 --cluster-slaver --cluster-master-id 新主机节点ID
    redis-cli --cluster add-node 192.168.238.80:6388 192.168.238.80:6387 --cluster-slave --cluster-master-id 6899abd525f6a3088cbc345a2efcbd333de4f02e
  8. 检查集群情况第3次

 主从缩容案例

  1. 检查集群情况1获得6388的节点ID : redis-cli --cluster check 192.168.238.80:6382
  2. 将6388删除,从集群中将4号从节点6388删除 : redis-cli --cluster del-node ip:从机端口号 从机6388节点ID
    redis-cli --cluster del-node 192.168.238.80:6388 aadd958f00fec4424a340844854a9cf95781d922
  3. 将6387的槽号清空,重新分配,本例将清出来的槽号都给6381 :
    redis-cli --cluster reshard 192.168.238.80:6381
  4. 检查集群情况第2次
    1. 将6387删除 :redis-cli --cluster del-node ip:端口号 6387节点ID
redis-cli --cluster del-node 192.168.238.80:6387 6899abd525f6a3088cbc345a2efcbd333de4f02e
  1. 检查集群情况第三次

2.DockerFile解析

        Docker是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

  dockerfile保留字指令:tomcat/Dockerfile at master · docker-library/tomcat · GitHub

  • FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
  • MAINTAINER:镜像维护者的姓名和邮箱地址
  • RUN:容器构建时需要运行的命令;RUN是再docker build时运行;两种格式:
    • shell格式
    • exec格式
  • EXPOSE:当前容器对外暴露出的端口
  • WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
  • USER:指定该镜像以什么样的用户去执行,如果都不指定,默认是root
  • ENV:用来在构建镜像过程中设置环境变量
  • ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
  • COPY:类似ADD,拷贝文件和目录到镜像中,将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内<目标路径>位置:
    • COPY src dest
    • COPY ["src","dest"]
    • <src源路径>:源文件或者源目录
    • <dest目录路径>:容器内的指定路径,该路径不用事先建好
  • VOLUME:容器数据卷,用于数据保存和持久化工作
  • CMD: 指定容器启动后要干的事情
    • 注意:Dockerfile中可以有多个CMD指定,但只有最后一个生效,CMD会被docker run之后的参数替代
    • 它和RUN命令的区别:
      • CMD是在docker run 时运行
      • RUN是在 docker build时运行
  • ENTRYPOINT: 也是用来指定一个容器启动时要运行的命令。类似于CMD指令。但是ENTRYPOINT不会被docker run 后面的命令覆盖,而且这些命令行参数会被当作参数送给ENTRYPOINT指令指定的程序

案例

        自定义镜像mycentosjava8:

        要求:centos7镜像具备vim + ifconfig + jdk8

        JDK下载:Java Downloads | Oracle

  1. 准备编写Dockerfile文件 ,在压缩包同一目录下创建Dockerfile文件:
FROM centos7.6.1810
MAINTAINER zcl

ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux.x64.tar.gz添加到容器中,安装包必须要和Dckerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80
CMD echo $MYPATH
CMD echo "success---------------ok"
CMD /bin/bash

     2.构建:docker build -t 新镜像名字:TAG .      注意TAG后面有个空格,有个点

docker build -t centosjava8:1.5 .

        3.运行:docker run -it 心镜像名:TAG

docker run -it 87ea3c3e1155 /bin/bash

虚悬镜像

        虚悬镜像:仓库名,标签名都是<none>的镜像,俗称dangling image

        删除:docker image prune


3.Docker微服务                

        一.通过IDEA新建一个普通微服务模块

package com.example.docker.controller;/**
 * @Author: ZCL
 * @DATE: 2022/11/8 21:07
 */

import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

/**
 * @program: docker-boot
 * @author: ZCL
 * @create: 2022-11-08 21:07
 */
@RestController
public class OrderController {

    @Value("${server.port}")
    private String port;

    @RequestMapping("/order/docker")
    public String helloDocker(){
        return "hello docker"+"/t"+port+"/t"+ UUID.randomUUID().toString();
    }

    @RequestMapping(value = "/order/index",method = RequestMethod.GET)
    public String index(){
        return " 服务端口号"+"/t"+port+"/t"+ UUID.randomUUID().toString();
    }
}

        二.通过dockerfile发布微服务部署到docker容器

                1.编写dockerfile

#基础使用镜像java
FROM java:8
#作者
MAINTAINER zcl
#VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建一个临时文件并链接到容器的/tmp
VOLUME /tmp
#将jar包添加到容器中并更名为zcl_docker.jar
ADD docker-0.0.1-SNAPSHOT.jar zcl_docker.jar
#运行jar包
RUN bash -c 'touch /zcl_docker.jar'
ENTRYPOINT ["java","-jar","/zcl_docker.jar"]
#暴露6001端口号作为微服务
EXPOSE 6001

                2.构建

docker build -t zcl_docker:1.6 .

                3.运行容器  

 docker run -d -p 6001:6001 ab6314e8f16a

                4.访问微服务


4.Docker网络

能干什么:容器间的互联和通信以及端口映射

                :容器IP变动时候可以通过服务名直接网络通信而不受影响

        docker启动后其网络情况:

查看docker网络模式:docker network ls

 常用命令

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

查看网络:docker network ls

查看网络源数据:docker network inspect 网络名字

删除网络:docker network rm 网络名字

网络模式:

网络模式简介
bridge

为每一个容器分配,设置IP等,并将容器链接到一个docker0

虚拟网桥,默认为该模式

host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
none容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配wrth pair 和网桥连接,IP等
container新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等


bridgeDocker服务器默认会创建一个docker0网桥(其上有一个docker0内部接口),这桥接网络的名称为docker0,它在内部层连接了其他的物理或虚拟网卡,这就是将所有容器和本地主机都放到同一个物理网络,Docker默认指定docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

案例:

        1.启动两个tomcat容器

 docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8

 原理:

        1.整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair)

        2.每个容器实例内部也有一块网卡,每个接口叫eth0;

        3.docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配

通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。 

 


host:直接使用宿主机的IP地址与外界直接进行通信,不在需要额外进行NAT转换

原理:容器将不会获得一个独立的Nwtwork Namespace ,而是和宿主机公用一个Network Namespace,容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口

 案例:

docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8

2.  查看tomcat83网络数据源:docker inspect tomcat83

 3.进入tomcat83:docker exec -it tomcat83 bash  :发现与宿主机的网络配置一样


 none:禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)

在none模式下,并不为Docker容器进行任何网络配置,也就是说,这个Docker容器没有网卡,IP,路由等信息,只有一个lo,需要我们自己为Docker容器添加网卡,配置IP等。

案例:

docker run 8084:8080 --network none --name tomcat84 billygoo/tomcat -jdk8

 

3.进入内部查看:只有一个lo 


 container:新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享,新建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定容器共享IP,端口范围等,同样,两个容器除了网络方面,其他的如文件系统,进程列表等还是隔离的。

 案例:

错误案例

docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
docker run -d -p 8086:8080 --name container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8

 tomcat86与tomcat85公用一个ip同一个端口,导致端口冲突

正确案例 :Alpine操作系统是一个面向安全的轻型Linux发行版

docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh

分别进入两个容器中,发现alpine2使用的是alpine1的网络配置,当alpine1共享源关闭后,alpine2就没有自己的配置了


自定义网络

案例:

        1.自定义桥接网络,自定义网络默认使用的是桥接网络bridge

        2.新建自定义网络        : docker network create a_network

        3.新建容器加入上一步新建的自定义网络

docker run -d -p 8081:8080 --network a_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network a_network --name tomcat82 billygoo/tomcat8-jdk8

        4.互相ping测试


5.Docker-compose容器编排

        Docker_compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排,可以管理多个Docker容器组成一个应用,你需要定义一个YAML格式的配置文件docker-compose.yml,写好多个容器之间的调用关系,然后只需要一个命令,就能同时启动/关闭这些容器

Overview | Docker Documentation

安装

1curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

2.chmod +x /usr/local/bin/docker-compose

3.docker-compose --version

Maven打包命令

 >mvn clean install -Dmaven.test.skip=true

将jar放到mydocker目录下

编写Dockerfile

#基础使用镜像java
FROM java:8
#作者
MAINTAINER zcl
#VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建一个临时文件并链接到容器的/tmp
VOLUME /tmp
#将jar包添加到容器中并更名为zcl_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zcl_docker.jar
#运行jar包
RUN bash -c 'touch /zcl_docker.jar'
ENTRYPOINT ["java","-jar","/zcl_docker.jar"]
#暴露6001端口号作为微服务
EXPOSE 6001

 build

 docker build -t zcl_docker:1.7 .

 Docker-compose.yml 在mydocker目录下


 version: "3"

 services:
    microService:
      image: zcl_docker:1.7
      container_name: ms01
      ports:
        - "6001:6001"
      volumes:
        - /app/microService:/data
      networks:
        - zcl_net
      depends_on:
        - redis
        - mysql

    redis:
      image: redis:6.0.8
      ports:
        - "6379:6379"
      volumes:
        - /app/redis/redis.conf:/etc/redis/redis.conf
        - /app/redis/data:/data
      networks:
        - zcl_net
      command: redis-server /etc/redis/redis.conf


    mysql:
      image: mysql:5.7
      environment:
         MYSQL_ROOT_PASSWORD: '123456'
         MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
         MYSQL_DATABASE: 'dbdocker'
         MYSQL_USER: 'root'
         MYSQL_PASSWORD: '123456'
      ports:
        - "3306:3306"
      volumes:
        - /app/mysql/db:/var/lib/mysql
        - /app/mysql/conf/my.cnf:/etc/my.cnf
        - /app/mysql/init:/docker-entrypoint-initdb.d
      networks:
        - zcl_net
      command: --default-authentication-plugin=mysql_native_password

 networks:
    zcl_net:

 修改原来项目的配置。重新打包成jar

 检查docker-compose 中是否存在语法错误:docker-compose config -q

 执行docker-compose up 或者 docker-compose up -d


Pointainer的安装

Powerful container management software for Platform Teams, DevOps, Dev

命令安装:

 docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

1.第一次登录需创建admin,访问地址:本机IP:9000

2.设置admin用户和密码后首次登录密码八位

3.选择local选项卡后本机docker详细信息展示


容器监控3剑客:CAdivsor监控收集+InfluxDB存储数据+Granfana 数据分析

docker-compose容器编排:

        

version: '3.1'
 
 
 
volumes:
 
  grafana_data: {}
 
 
 
services:
 
 influxdb:
 
  image: tutum/influxdb:0.9
 
  restart: always
 
  environment:
 
    - PRE_CREATE_DB=cadvisor
 
  ports:
 
    - "8083:8083"
 
    - "8086:8086"
 
  volumes:
 
    - ./data/influxdb:/data
 
 
 
 cadvisor:
 
  image: google/cadvisor
 
  links:
 
    - influxdb:influxsrv
 
  command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
 
  restart: always
 
  ports:
 
    - "8080:8080"
 
  volumes:
 
    - /:/rootfs:ro
 
    - /var/run:/var/run:rw
 
    - /sys:/sys:ro
 
    - /var/lib/docker/:/var/lib/docker:ro
 
 
 
 grafana:
 
  user: "104"
 
  image: grafana/grafana
 
  user: "104"
 
  restart: always
 
  links:
 
    - influxdb:influxsrv
 
  ports:
 
    - "3000:3000"
 
  volumes:
 
    - grafana_data:/var/lib/grafana
 
  environment:
 
    - HTTP_USER=admin
 
    - HTTP_PASS=admin
 
    - INFLUXDB_HOST=influxsrv
 
    - INFLUXDB_PORT=8086
 
    - INFLUXDB_NAME=cadvisor
 
    - INFLUXDB_USER=root
 
    - INFLUXDB_PASS=root

docker-compose config -q 检查错误

docker-compose up 启动

测试

acdvisor:     http://192.168.238.80:8080   

influxdb :  http://192.168.238.80:8083/

Grafana  :  http://192.168.238.80:3000/

为grafana配置数据源:

        

 选择influxdb为数据源:

 

面板panel的添加:

 选择图形化展示方式:

  • 19
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
抱歉,我发现我的回答不完整了。以下是完整的回答: 当panel1中随时会垂直添加新的panel2时,可以将panel1放在一个JScrollPane里,当panel1中的内容超出JScrollPane的大小时,就会自动添加滚动条来显示内容。 下面是一个例子,演示了如何为panel1添加滑动条: ```java import javax.swing.*; import java.awt.*; public class ScrollPaneExample { public static void main(String[] args) { JFrame frame = new JFrame("Scroll Pane Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 300); // 创建一个panel1,随时会垂直添加新的panel2 JPanel panel1 = new JPanel(); panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); for (int i = 0; i < 10; i++) { JPanel panel2 = new JPanel(); panel2.add(new JLabel("Panel " + i)); panel1.add(panel2); } // 创建一个滚动面板,将panel1添加到其中 JScrollPane scrollPane = new JScrollPane(panel1); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); // 将滚动面板添加到frame中 frame.getContentPane().add(scrollPane); frame.setVisible(true); } } ``` 在这个例子中,我们创建了一个panel1,使用BoxLayout布局管理器使其可以随时垂直添加新的panel2。然后,将panel1添加到了一个滚动面板中,并将垂直滚动条的显示策略设置为始终显示。最后,将滚动面板添加到frame中。当panel1中的panel2数量过多时,就会出现垂直滚动条,从而可以实现滚动功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Maserati477

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值