Docker初体验


前言

    随着业务的发展,传统的架构已经不符合项目的要求了。双活、集群也渐渐提上了日程。。。


一、就是你了——Docker

    最近接到一个需求,生产上要搭建双活环境。再加上现在已有的集群,动辄十几台机子。所有机子都要安装一遍redis、nginx,这工作量简直不可想象。而且各个机子的配置,软件版本存在差异,把测试环境的软件包拿过去安装,发现版本对不上,导致安装失败,简直让人崩溃。经过一番考量后,最后选择docker进行部署,一来可以屏蔽系统之间的差异,不用再在环境上浪费时间。二来搭配自动部署的工具,就算是几十台机子也不用一遍又一遍做重复的工作

二、Docker概览

    一说到docker,想必大家脑海里都会浮现一只鲸鱼驮着一堆集装箱的图片,鲸鱼驮着一堆集装箱游走在各个海域。事实也是如此,鲸鱼就是docker,而集装箱,就是我们装的软件,海域则是不同的环境

在这里插入图片描述

    docker简单来说,可以理解成一个mini版的虚拟机。那为什么不直接用Vmware而是用docker,主要还是因为Vmware太重了,像平时用Vmware装个Linux系统,动辄4C4G起步,装的软件一多还得继续往上砸硬件,显然这成本就太高了。docker就是基于这种情况下出现的,之所以轻量级,是除了软件必虚的环境之外,不安装多余的东西。之所以可移植,是docker屏蔽了环境之间的差异,如果说是java是一次编译,四处运行。那么docker就是一次打包,四处部署(相对而言)。计算机的世界,果然没有什么是加一层不能解决的,如果有,那就再加一层

注:docker貌似没有实现真正意义上的跨平台,还是依赖于操作系统,在部署的过程中,发现Linux打包的镜像无法再Windows部署,不过细想下:docker打包的镜像包含操作系统,Linux下打包的镜像,自然无法导入Windows。貌似也没毛病

在这里插入图片描述

三、 Docker架构

    了解完docker,接下来再来看下docker的架构,看下docker具体怎么执行的。下边是官方给出的流程图,如下:

在这里插入图片描述

    可以看出,Docker主要分为:客户端、守护进程、仓库、镜像 这几部分。下边就一一来看下这几个某块分别的作用

守护进程(Docker daemon)

    守护进程docker最核心的部分。负责处理客户端请求,docker资源,如:镜像、容器、网络都是由守护进程在管理

客户端(Docker client)

    客户端就比较简单了,像平时敲得命令:docker、docker-compose 都属于客户端客户端负责向守护进程发起请求

镜像(Images)、容器(Containers)

    镜像(Images)、容器(Containers)、网络(networks)、卷(volumes)都属于docker对象的一部分,这里主要说说下镜像和容器

    镜像容器的关系有点类似于对象的关系,镜像提供只读模板,容器创建具体内容

仓库(Docker registries)

    仓库就比较好理解了,现在一般会部署集群,这时候如果没有仓库,就需要把各个镜像上传到对应的服务器再进行安装,这显然不符合快速部署的要求。所以,一般会把镜像发布在公共仓库上,docker自己去下载即可

    那么这几个组件之间是如何配合工作的呢?以docker run 命令为例,大体流程:客户端发起请求,守护进程先查看本地是否存在镜像,不存在则去仓库下载,而后创建出容器。

访问
存在
不存在
下载
开始
docker
daemon
本地存在?
本地
仓库
结束

四、 Docker安装

    知道了docker的作用,直接开始撸袖子干。docker安装分为在线、离线。由于云上机子不能联网,所以这里重点聊下离线安装。其他安装方式可以参考官方安装文档,这里有详细说明

离线安装步骤
  1. 下载tgz包
    先去官网下载tgz包,这里选择的是20.10.5版本(根据自己实际需求选择

在这里插入图片描述

  1. 解压文件
 tar -zxvf docker-20.10.5.tgz

在这里插入图片描述

  1. 移动到对应目录
cp docker/* /usr/bin/

在这里插入图片描述

  1. 配置阿里镜像加速
    由于docker是外国人的东西,所以仓库默认连的是外网,需要给它提提速。国内加速方式也挺多的,如:百度、阿里、交大等。这里就以阿里云的镜像加速器为例。如下:

在这里插入图片描述

步骤写的很清楚,跟着操作就是了,这里使用离线安装,还没有配置系统服务,后面两步先省略。如下:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["加速地址"]
}
EOF
  1. 启动并验证
    现在只需要启动docker即可,命令如下:
nohup dockerd &

在这里插入图片描述

      docker已经启动完成,接着启动个nginx验证一下。命令如下:

docker run -itd --name nginx -p 8080:80 nginx

在这里插入图片描述

通过ip:8080访问,如下:

在这里插入图片描述

      可以看到,nginx已经启动完毕。回想之前在没有docker的情况下,安装nginx还得自己编译,是不是感觉方便了许多

在这里插入图片描述

  1. 注册系统服务
    接着还需要把docker注册为系统服务,方便Linux管理和启停
#写入service文件
tee /etc/systemd/system/docker.service <<- 'EOF'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target

[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

#设置开机自启
systemctl enable docker

#启动docker
systemctl start docker


注:如果启动过程中遇到:Job for docker.service failed because start of the service was attempted too often. 则执行systemctl reset-failed docker.service 即可


如果遇到:Job for docker.service failed because the control process exited with error code.
See “systemctl status docker.service” and “journalctl -xeu docker.service” for details。看下服务配置,如下:

# Ubuntu的路径; CentOS 的路径为: /usr/lib/systemd/system/docker.service
vim /lib/systemd/system/docker.service

#修改文件内容:
#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecStart=/usr/bin/dockerd

#重新启动docker服务
service dockerd  restart


docker.sock 是 Docker 守护进程的通信接口,而 containerd.sock 是 containerd 的通信接口。两者在功能和使用场景上有所不同。docker.sock是一个完整的容器平台,包括了容器运行时、镜像管理、网络和存储等多个方面的功能,而 containerd.sock 则更加专注于容器的生命周期管理。因此,在选择使用哪个套接字时,取决于你的具体需求和应用场景


如果还是不行,那只能重启了

在这里插入图片描述

五、搭建Docker私服

    云上开发,最不方便的地方就是不能连外网,查资料,下载东西非常麻烦。上边配置的docker仓库,就无法连接上阿里云,这时候就需要搭建docker私服

    搭建docker私服有几种方式:registry、nexus、harbor 这里逐一搭建下吧

Registry

    registry 是官方提供的镜像仓库。仅能使用api和json进行操作,不够友好,所以一般情况下不用这个,了解即可

  1. 运行registry
docker run -itd -p 5000:5000 --name registry   registry

访问:http://ip:5000/v2/_catalog,不出意外的话,会出现以下界面:

在这里插入图片描述

  1. 推送镜像
    在操作之前,需要配置一下/etc/docker/daemon.json文件,具体配置如下:
{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["registry-ip:5000"]
}

重启下docker

systemctl daemon-reload
systemctl restart docker

这样私有仓库就配置完成了

在上传进行之前还需要重命名下镜像 的名称,docker会根据镜像名称选择上传的仓库。如下:

#重命名成registry仓库地址
docker tag nginx 192.168.233.130:5000/nginx
#上传镜像
docker push 192.168.233.130:5000/nginx

在这里插入图片描述

再次访问:http://ip:5000/v2/_catalog,出现nginx镜像。如下:

在这里插入图片描述

  1. 拉取镜像
    执行下列命令从私服拉取镜像:
docker pull  192.168.233.130:5000/nginx

在这里插入图片描述

注:这里拉取的时候需要添加私服地址,这涉及到docker镜像命名的问题,如果直接通过镜像拉取,并不是像Maven那样:先去私服找,再去公网找,即使配置了私服地址也没用,官方貌似拒绝了这个提案。RedHat系统可以添加 --add-registry 和 --block-registry 进行覆盖,其他系统就不行了,github也有相应的讨论

在这里插入图片描述
在这里插入图片描述

Nexus

    现在docker镜像的工具已不少了,之所以带Nexus玩,主要还是因为之前Maven私服也是用Nexus搭建的,这样可以充分利用资源。嘿嘿~~

  1. 安装Nexus
    Nexus还是用docker进行安装,先启动Nexus,命令如下:
docker run -d -p 8081:8081 -p 8082:8082 -p 8083:8083 -v /etc/localtime:/etc/localtime --name nexus3   sonatype/nexus3

在这里插入图片描述
Nexus3默认用户名是admin,密码需要进入容器内部进行查看。如下:

#进入容器内部
docker exec -it nexus3 bash
tail -200f /nexus-data/admin.password

2.创建仓库
现在只需要在Nexus提供的界面上建立docker仓库即可。具体步骤如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

按照上面配置直接创建仓库即可。创建完成Nexus会多个docker仓库

在这里插入图片描述

  1. 推送镜像
    推送镜像和Registry一样,配置一下/etc/docker/daemon.json文件。如下:
{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["nexus-ip:8082","registry-ip:5000"]
}

重启下docker

systemctl daemon-reload
systemctl restart docker

接着需要先登录到NexusNexus存在权限校验)再进行推送。如下:

#登录Nexus
docker login -u admin -p admin nexus-ip:8082
#重命名成nexus私库地址
docker tag nginx 192.168.233.130:8082/nginx
#推送镜像
docker push 192.168.233.130:8082/nginx

在这里插入图片描述

在这里插入图片描述

  1. 拉取镜像
    拉取镜像和Registry一样了,就不一一赘述了

注:不论是Registry还是Nexus,这里只是简单的示例,无法用于实际环境。如果确定使用docker部署,要把数据持久化到服务器,否则容器终止,数据也会消失

Harbor

    接下来欢迎本次的主角——Harbor。以下是它的自我介绍:

Harbor 是一个开源可信云原生注册表项目,用于存储、签名和扫描内容。 Harbor 通过添加用户通常需要的功能(例如安全性、身份和管理)来扩展开源 Docker 发行版。让注册表更接近构建和运行环境可以提高映像传输效率。 Harbor 支持注册表之间的镜像复制,还提供高级安全功能,例如用户管理、访问控制和活动审核

看不懂,反正很厉害就是了。还是先学会怎么用吧
在这里插入图片描述

  1. 下载Harbor
    虽然Harbor是用docker部署的,但是分为几个模块,官方对其进行了整合,还是得下载下安装包。先去官方的github整个安装包(根据实际情况选择版本),这里以2.9.1为例

  2. 解压

tar -zxvf  harbor-offline-installer-v2.9.1.tgz

解压后的目录结构,如下:

在这里插入图片描述

可以看到Harbor已经准备好了一切

  1. 安装
    在正式安装之前,先改下文件夹名称、添加下配置文件:
mv harbor harbor-install
cd harbor-install
cp harbor.yml.tmpl harbor.yml

再修改下配置文件,打开harbor.yml,参考配置如下:

#主机名,这里改成ip
hostname: 192.168.233.130
http:
#访问端口,根据实际情况配置
  port: 8080

# https相关配置,这里不需要,直接注释,否则会报错
#https:
#  port: 443
#  certificate: /your/certificate/path
#  private_key: /your/private/key/path

#登录密码
harbor_admin_password: Harbor12345

# Harbor DB configuration
database:
  password: root123
  max_idle_conns: 100
  max_open_conns: 900
  conn_max_lifetime: 5m
  conn_max_idle_time: 0

# 数据存储位置
data_volume: /usr/local/docker/harbor/data

trivy:
  ignore_unfixed: false
  skip_update: false
  offline_scan: false
  security_check: vuln
  insecure: false
  
jobservice:
  max_job_workers: 10
  job_loggers:
    - STD_OUTPUT
    - FILE
  logger_sweeper_duration: 1 #days

notification:
  webhook_job_max_retry: 3
  webhook_job_http_client_timeout: 3 #seconds

log:
  level: info
  local:
    rotate_count: 50
    rotate_size: 200M
    #日志存储位置
    location: /usr/local/docker/harbor/logs

_version: 2.9.0

proxy:
  http_proxy:
  https_proxy:
  no_proxy:
  components:
    - core
    - jobservice
    - trivy


upload_purging:
  enabled: true
  age: 168h
  interval: 24h
  dryrun: false

cache:
  enabled: false
  expire_hours: 24

配置完成后,直接安装即可:

./install.sh

在这里插入图片描述

直接访问ip:8080(端口、密码根据上边配置进行填写

在这里插入图片描述

在这里插入图片描述

  1. 推送镜像
    在推送镜像之前,先新增一个项目:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

接下来的操作,就和Nexus大同小异了。配置/etc/docker/daemon.json文件。如下:

{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["harbor-ip:8080","nexus-ip:8082","registry-ip:5000"]
}

重启docker

systemctl daemon-reload
systemctl restart docker

登录、推送。如下:

#登录到Harbor
docker login -u admin -p Harbor12345 192.168.233.130:8080
#重命名为Harbor地址
docker tag nginx 192.168.233.130:8080/test/nginx
#推送到Harbor
docker push 192.168.233.130:8080/test/nginx

相较于NexusHarbor 路径多了个test,这个即之前创建的项目名

在这里插入图片描述

  1. 拉取镜像
    拉取镜像和推送一样,需要带上项目名:
docker pull 192.168.233.130:8080/test/nginx

六、Dockerfile自定义镜像

    前边一直操作别人提供好的镜像,在实际工作中,往往都有我们自己的项目,这时候需要自己构建镜像并提交到私库,方便运维人员进行部署

    先用Idea创建一个简单的Springboot项目。具体步骤想必大家都懂,这里就不赘述了。重点看下pom.xml文件。如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>docker-demo</artifactId>
    <version>1.0</version>
    <name>docker-demo</name>
    <description>docker测试项目</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>docker-demo</finalName>
        <plugins>
            <!-- docker插件 -->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.2</version>
                <configuration>
                    <!-- 镜像名称,'[a-z0-9-_.]'格式 -->
                    <imageName>${project.artifactId}:${project.version}</imageName>
                    <dockerDirectory>${project.basedir}/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                            <include>classes/application.*</include>
                        </resource>
                    </resources>
                    <!--这里用tcp,用提示协议错误-->
                    <dockerHost>http://192.168.233.135:2375</dockerHost>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.example.dockerdemo.DockerDemoApplication</mainClass>
                    <skip>false</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

    构建镜像需要用到Dockerfiledocker 通过读取 Dockerfile 中的指令来自动构建镜像。通常,一个镜像基于另一个镜像,就像千层饼一样一层套一层。接下来就看下如何把jar文件打包成镜像吧。显然,Jdk镜像是我们的基础镜像Dockerfile如下:

#引入jdk镜像
FROM openjdk:8-jre-slim
# 作者名
MAINTAINER hqd

#设置中国时区,否则容器内部时间显示美国时间。和实际时间对不上
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

ADD docker-demo.jar /app.jar
ADD classes/application.* /config/
#创建具有指定名称的安装点,并将其标记为保存来自本机主机或其他容器的外部安装卷
VOLUME config
#实际上并未发布端口。它充当构建映像的人员和运行容器的人员之间的一种文档,有关要发布哪些端口。使用-p进行覆盖
EXPOSE 8080
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS"]

接下来,只需要构建镜像即可,构建方式主要有两种:命令行和远程。下边都来看下吧

命令行

    命令行构建需要把构建所需的文件放到服务器上(需要docker环境)。目录结构如下:

在这里插入图片描述
而后,执行docker命令进行构建,如下:

# .即当前目录,t即tag,为镜像名称
 docker build . -t docker-demo:1.0

在这里插入图片描述

如果出现异常,会产生仓库名、标签都是none的镜像,即虚悬镜像

在这里插入图片描述
这时候只需执行清理即可,如下:

#清理镜像
docker image prune
#清理系统
docker system prune
远程

    现在基本都是用Maven进行开发,我们更希望直接通过Maven进行远程部署,这时候就需要用到DockerMaven插件

  1. docker开启2375端口
    想要远程构建镜像docker需要先开启端口进行通信,修改 /etc/docker/daemon.json 文件,如下:
{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["harbor-ip:8080","nexus-ip:8082","registry-ip:5000"]
  "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
}

重启docker

systemctl daemon-reload
systemctl restart docker
  1. 项目添加Dockerfile
    再把Dockerfile添加到项目中。如下:

在这里插入图片描述

  1. 添加DockerMaven插件
    再引用下DockerMaven插件,上面的pom.xml已经给出全部配置,这里主要看下插件部分。如下:
 <plugin>
     <groupId>com.spotify</groupId>
     <artifactId>docker-maven-plugin</artifactId>
     <version>1.2.2</version>
     <configuration>
         <!-- 镜像名称,'[a-z0-9-_.]'格式 -->
         <imageName>${project.artifactId}:${project.version}</imageName>
         <dockerDirectory>${project.basedir}/docker</dockerDirectory>
         <resources>
             <resource>
                 <targetPath>/</targetPath>
                 <directory>${project.build.directory}</directory>
                 <include>${project.build.finalName}.jar</include>
                 <include>classes/application.*</include>
             </resource>
         </resources>
         <!--这里用tcp,用提示协议错误-->
         <dockerHost>http://服务器Ip:2375</dockerHost>
     </configuration>
 </plugin>
  1. 构建镜像
    点击Idea右侧Maven进行构建。如下:
    在这里插入图片描述

七、命令繁琐?那就用docker-compose

    生产上往往不止一台机子,而部署的应用也有很多。一条条命令去敲也很麻烦,需要对进行容器编排,方便管理。现在比较流行的容器编排是k8s,目前这个项目用不到,这边只用docker-compose即可。至于什么是docker-compose,简单来说:就是把多个容器的运行命令写到YAML文件中去,这样方便统一管理,易于共享

  1. 下载
    老样子,先下载docker-compose,这里用的是v2.24.5(根据自己需求选择)

在这里插入图片描述

  1. 安装
    把下载好的文件上传至服务器,执行命令:
#重命名文件
mv docker-compose-linux-x86_64 docker-compose
#添加执行权限
chmod u+x docker-compose
#移动到系统目录
mv docker-compose /usr/bin/
#查看版本
docker-compose -v

在这里插入图片描述

  1. 验证
    之前启动镜像都是用命令行直接启动,现在体验一下docker-compose,看看为什么选择它。就以之前提到的docker-demonginx为例

docker-demo配置和之前的一样,不做改动。nginx配置文件如下:


user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
	
	server {
       listen       80;
       server_name  192.168.233.135;
       location / {
            proxy_read_timeout 300;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://docker-demo:8080;
        }
	}

}

注:其他配置大家应该都不陌生,可能会对proxy_pass http://docker-demo:8080感到疑惑,这个涉及到docker网络部分,后边会聊到

编写YAML文件如下:

version: '2' # 表示该 Docker-Compose 文件使用的是 Version 2 file
services:
  docker-demo:  # 服务名称
    image: docker-demo:1.0
    container_name: docker-demo #容器名称
#    build: /usr/local/docker/docker-demo   # 指定 Dockerfile 所在路径
    ports:    # 指定端口映射
      - "8080:8080"
    volumes:
      - /usr/local/docker/docker-demo/classes:/config
      
    networks:
      - docker-demo
      
  nginx:  # 服务名称
    image: nginx
    container_name: nginx #容器名称
    ports:    # 指定端口映射
      - "8081:80"
    volumes:
      - /usr/local/docker/nginx/logs:/var/log/nginx
      - /usr/local/docker/nginx/config/nginx.conf:/etc/nginx/nginx.conf
      
    networks:
      - docker-demo


networks:
  docker-demo:
    driver: bridge #使用桥接创建网络


接着,进去docker-compose文件所在目录,执行启动命令:

#启动所有应用,-d后台启动
docker-compose -f docker-demo.yml up -d
#关闭所有应用
docker-compose -f docker-demo.yml down
#重启所有应用
docker-compose -f docker-demo.yml restart

在这里插入图片描述

在这里插入图片描述

应用起来了,疑惑也起来。下边就来看下volumes(数据卷)networks(网络)

networks(网络)

    玩过Vmware的应该配置过它的网络,以前该接触时,要么主机ping不通虚拟机,要么虚拟机ping不通主机,对此没少百度。现在回头再来看,Vmware的网络大致分为:

  • 桥接
    桥接模式下,虚拟机和宿主机都会连接到虚拟交换机上,宿主机的网卡与虚拟机的虚拟网卡通过虚拟网桥连接起来,它们的地位“平等”,同处于一个网段互不干拢,虚拟机是网络的完整参与者

阿道夫地方

  • NAT
    NAT模式下,虚拟机在外部网络上没有自己的 IP 地址。相反,在宿主机上设置一个专用网络。其原理是将专用网络中虚拟机的 IP 地址转换为主机系统的 IP 地址。当虚拟机发送访问网络资源的请求时,网络资源看起来就像该请求来自主机系统。这样看来,宿主机像是虚拟机的“上级”
    撒大声地

  • 仅主机
    仅主机模式下,虚拟机和主机虚拟网络适配器连接到专用以太网,虚拟机只能和主机通信,不能与外网进行通信,相当于一个封闭的局域网
    撒大大

跑题了~,回到docker,再看下docker的网络:

  • Bridge
    Bridge模式虽然叫Bridge,但是并不等价于Vmware的桥接,而是与NAT模式相似,docker会在宿主机创建一个docker0网卡,该网卡会与一个虚拟交换机相连,当容器Bridge模式创建启动时,会给容器创建一个虚拟网卡,该网卡分配的IP与宿主机的docker0所在同一个局域网内

  • Host
    Host模式会直接使用宿主机的网卡,容器本身并不会创建虚拟网卡,容器暴露的端口可以直接在宿主机中查到,可以当成就是在宿主机真实执行的程序。使用此模式时 -p 参数失效

  • Container
    Container模式会指定一个容器的网卡为网卡,当前容器也不会创建虚拟网卡。这两个容器不能有一样的端口暴露

  • None
    None模式不会给容器创建网卡,相当于一个没有网卡的机子,无法与外部通讯

  • Overlay
    Overlay模式是为了在多个docker守护进程主机之间创建分布式网络,即不同机子上部署的docker可以相互通讯,该模式允许连接到它的容器(包括集群服务容器)安全地通信

  • IPvlan
    IPvlan模式比较麻烦,没看懂,直接摘取官网的描述:IPvlan 是经过考验的真实网络虚拟化技术的新变化。 Linux 实现非常轻量级,因为它们不是使用传统的 Linux 桥进行隔离,而是与 Linux 以太网接口或子接口相关联,以强制网络之间的分离以及与物理网络的连接。

    IPvlan提供了许多独特的功能,并为各种模式的进一步创新提供了充足的空间。这些方法的两个高级优势是,绕过 Linux 桥的积极性能影响以及移动部件较少的简单性。移除传统上位于 docker 主机 NIC 和容器接口之间的桥接器,留下由直接连接到 docker 主机接口的容器接口组成的简单设置。面向外部的服务很容易访问此结果,因为在这些场景中不需要端口映射

IPvlan L2
在这里插入图片描述

  • Macvlan
    Macvlan模式一样没看懂,官网描述:某些应用程序,尤其是遗留应用程序或监视网络流量的应用程序,期望直接连接到物理网络。在这种情况下,您可以使用Macvlan网络驱动程序为每个容器的虚拟网络接口分配一个MAC地址,使其看起来像是直接连接到物理网络的物理网络接口。在这种情况下,您需要在docker主机上指定用于 Macvlan的物理接口,以及网络的子网和网关。您甚至可以使用不同的物理网络接口隔离 Macvlan 网络

在这里插入图片描述

volumes(数据卷)

    volumes又是个麻烦的话题。简单来说,是为了方便备份或迁移,以及共享。前文提到过,如果没有volumes(命令行的 -v 或 --mount 、Docker Composevolumes),一旦容器挂了,数据就会丢失,类似于数据库这样的应用,怕是牢饭管饱。。。

    为了避免牢饭管饱,就需要把容器内的数据映射到宿主机上边保存,这也是volumes主要作用

在这里插入图片描述

八、Docker监控

    用docker启动好各个应用后,还需要对各个应用进行监控,如果哪台服务挂了,方便定位重启。监控工具主要是:

Portainer

官方介绍

是一个针对容器化应用程序的轻量级服务交付平台,可用于管理 Docker、Swarm、Kubernetes 和 ACI 环境。它的设计理念是部署和使用都简单。该应用程序允许您通过“智能”GUI 和/或广泛的 API 管理所有编排器资源(容器、图像、卷、网络等)

巴拉巴拉,只要记住是轻量级的容器管理平台就行了。Portainer分为社区版(CE)和商业版(BE),当然,这里用的是社区版。有了docker部署就很方便:

#创建数据卷
docker volume create portainer_data

#安装中文版
docker run -d -p 9000:9000 --name=portainer  -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data outlovecn/portainer-cn

在这里插入图片描述

再添加docker服务之前,被监听的docker需要开启2375端口

{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["harbor-ip:8080","nexus-ip:8082","registry-ip:5000"]
  "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
}

Portainer有多种监听方式,这里只演示docker API的方式

在这里插入图片描述

根据实际情况填写IP

在这里插入图片描述

首页就可以看到对应的docker环境

在这里插入图片描述

在这里插入图片描述

CIG

    既然存在轻量级,那必然就有重量级。接下来就来看下CIGCIG实际上是由三个组件组成:CAdvisorInfluxDBGrafana

  • CAdvisor
    CAdvisor 是由 Google 开源的一个用于监控容器资源使用情况的工具。它能够实时收集docker容器的 CPU 使用率、内存使用量、磁盘 I/O、网络流量 等指标,并将这些数据暴露为 Prometheus格式的监控端点

  • InfluxDB
    InfluxDB 是一个开源的时序数据库,专门设计用于处理时间序列数据。在 CIG 监控系统中,InfluxDB 用于存储由 CAdvisor收集的容器监控数据

  • Grafana
    Grafana 是一个开源的数据可视化工具,用于创建、查看和共享监控仪表盘。在 CIG 监控系统中,GrafanaInfluxDB 集成,可以直接从 InfluxDB 中查询容器监控数据,并通过可视化方式展示在用户界面上

编写cig.yml如下:

version: '2'
services:
 influxdb:
  image: tutum/influxdb:0.9
  container_name: influxdb
  environment:
    - PRE_CREATE_DB=cadvisor
  ports:
    - "8083:8083"
    - "8086:8086"
 
 cadvisor:
  image: google/cadvisor
  container_name: cadvisor
  links:
    - influxdb:influxsrv
  command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxdb:8086
  ports:
    - "8080:8080"
  volumes:
    - /:/rootfs:ro
    - /var/run:/var/run:rw
    - /sys:/sys:ro
    - /var/lib/docker/:/var/lib/docker:ro
 
 grafana:
  image: grafana/grafana
  container_name: grafana
  links:
    - influxdb:influxsrv
  ports:
    - "3000:3000"
   
  environment:
    - HTTP_USER=admin
    - HTTP_PASS=admin
    - INFLUXDB_HOST=influxsrv
    - INFLUXDB_PORT=8086
    - INFLUXDB_NAME=cadvisor
    - INFLUXDB_USER=root
    - INFLUXDB_PASS=root
#启动cig
docker-compose -f cig.yml up -d

访问http://192.168.233.135:8083/,查看是否创建cadvisor数据库。如下:
在这里插入图片描述

访问http://192.168.233.135:8080/containers/,查看CAdvisor自带的页面,如下:

在这里插入图片描述
访问http://192.168.233.135:3000/,用户名密码默认为admin,配置下Grafana折线图,如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

九、root权限被回收

    环境已经差不多了,root权限也要被收回了,之后只能使用普通用户进行操作。这就涉及到docker权限问题,由于之前没有指定用户,从容器内部挂载出来的目录都是root权限,普通用户是没有权限进行操作的,而且容器权限太高,有可能使主机被攻击。这又成了一个不得不解决的问题。先演示一下问题,还是用之前的YAML为例:

#删除原来nginx的日志路径
rm -rf /usr/local/docker/nginx/logs/
#赋予用户权限
chmod 777 /usr/bin/docker-compose
chmod 777 /var/run/docker.sock
#切换用户
su hqd
#启动
docker-compose -f docker-demo.yml up -d

在这里插入图片描述

可以看到,就算是用hqd用户启动,容器内映射到宿主机的路径也是root用户,这样hqd用户没权限进行任何操作

    幸运的是,docker官方也意识到了这点,并提供了解决方案——用户命名空间用户命名空间简单来说:就是用户映射,容器内部依旧是root用户操作,而容器内的root,实际上是宿主机的普通用户。像是地方长官在地方是老大,但是到了京城,最大的还得是皇帝

    接着看下如何指定用户命名空间

  1. 映射从属用户和组 ID
    先查看下需要指定用户的id和组id,这里我指定的用户是hqd
id hqd

在这里插入图片描述

这里用户id和组id都是1000,先记下,后边要用到

配置 /etc/subuid/etc/subgid

#1000就是上边查到的用户id
cat >> /etc/subuid <<-'EOF'
hqd:1000:1
hqd:100000:65536
EOF

#1000就是上边查到的组id
cat >> /etc/subgid <<-'EOF'
hqd:1000:1
hqd:100000:65536
EOF

这里配置需要注意,由于这里的subuidsubgid 是空的,所以可以直接写入,如果原本已经存在值需要往下递推,下边是个例子:

a:100000:65536

#165536 = 100000 + 65536
b:165536:65536

#231072 = 165536 + 65536
c:231072:65536

#296608 = 231072 + 65536
hqd:1000:1
hqd:296608:65536

如果是CentOS7,则需要下边配置:

#CentOS需要下边配置
echo "user.max_user_namespaces=15000" >> /etc/sysctl.conf

grubby --args="namespace.unpriv_enable=1 user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"

reboot

否则会出现下边错误:

在这里插入图片描述

  1. 启用 userns-remap

修改 /etc/docker/daemon.json 文件,如下:

{
  "registry-mirrors": ["加速地址"],
  //这里配置是让docker信任该地址,否则会提示https安全问题
  "insecure-registries":["harbor-ip:8080","nexus-ip:8082","registry-ip:5000"]
  "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"],
  //这里配置用户名:组名
  "userns-remap": "hqd:hqd"
}

开始测试:

systemctl daemon-reload
systemctl restart docker
#删除原有nginx日志
rm -rf /usr/local/docker/nginx/logs
#赋予docker相关命令权限
chmod 777 /usr/bin/docker*
#赋予docker.sock权限
chmod 777 /var/run/docker.sock
#切换成hqd用户
su hqd
#启动
docker-compose -f docker-demo.yml up -d

在这里插入图片描述

可以看到,logs文件夹已经变成了hqd用户所有了

用户命名空间已知限制,以下标准Docker功能与在启用了用户命名空间的情况下运行Docker守护程序不兼容:

  • 与主机(–pid=host或–network=host)共享PID或NET名称空间
  • 外部(卷或存储)驱动程序,这些驱动程序不知道或无法使用守护程序用户映射
  • –privileged在docker run未指定的情况下 使用mode标志–userns=host

    用户名称空间是一项高级功能,需要与其他功能配合。例如,如果从主机装载了卷,则必须预先安排文件所有权,需要对卷内容的读取或写入访问权限
    尽管用用户命名空间的容器进程中的root用户具有该容器内​​超级用户的许多预期特权,但Linux内核基于内部知识(这是一个用用户命名空间的过程)施加了限制。一个值得注意的限制是无法使用该mknod命令。由root用户运行时,在容器内创建设备的权限被拒绝

总结

    docker整体来说,提高了部署效率,特别是多环境下,可以屏蔽环境之间的差异,可以快速部署。但是docker本身也存在权限问题,编排问题,在用的过程中被整的很难受。当然,上边都是个人在使用docker时候的体验和理解,如果存在问题,欢迎大家指出
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

穷儒公羊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值