zoukankan      html  css  js  c++  java
  • Docker总结

    Docker简介

    简介

    # 官方定义
    - We have a complete container solution for you - no matter who you are and where you are on your containerization journey.
    - 翻译:我们为你提供完整的解决方案,无论你是谁无论你在哪里都可以开启你的容器之旅
    - 总结:在官方之中给的定义Docker属于一个容器技术
    

    Docker解决问题

    • 在开发阶段项目能够正确运行,但是在生产阶段代码不能正确运行

      在我们运行一个Django项目的时候,我们可能需要使用到MySQL Redis RabbitMQ Elasticsearch等,假如我们在Windows操作系统进行开发使用的版本为A,当我们将代码在Centos操作系统进行发布的时候可能使用的版本是B,由于版本使用的不一致导致代码运行环境有问题可能会出现各种异常,由于版本问题导致代码运行有问题会额外的给人员带来负担,如果我们使用Docker我们可以直接将运行的项目进行打包,直接使用Docker将代码项目发布即可,我们此时无需考虑使用本版,操作系统等问题,做到一次打包终身使用的效果。

      优点:一次打包终身使用,无需考虑版本操作系统等问题,只需要能够正常的运行Docker服务即可

    • 项目A内存资源被项目B所耗尽,导致项目A不能正常运行

      在生产环境中可能一个服务器同时运行多个项目,在项目A中所需要大量的资源最终将整个服务器资源耗尽,此时项目B由于无法得到正确的运行资源最终该项目无法正确对外运行,如果我们使用Docker运行项目,此时Docker在操作系统层面起到进程隔离效果,对每个容器分配单独的运行资源,这样每个项目就会拥有独立的运行资源互相隔离互不影响

      优点二:进程之间的隔离导致各个应用独立运行,互不影响

    • 简化部署,提高效率

      如果在比较大的项目之中可能需要使用到多台服务器充当生产环境,大量的服务器无论是运维还是环境搭建都是比较麻烦的,如果我们此时使用docker极大的降低了运维难度,减少了环境搭建的时间提高部署效率

      优点三:镜像复制保证多个节点环境一致

    Docker与虚拟机的区别

    dw

    • Docker体积轻巧

      在上图中我们可以看出如果在虚拟机中安装操作系统再次运行一些服务,导致原本轻量的虚拟机因为安装操作系统导致虚拟机特保笨重同时对于应用的迁移也时分不方便,而使用Docker可以看到其直接运行在物理机中的操作系统因此Docker十分轻便

    • Docker部署简便

      在Docker中只需要安装Docker当Docker安装成功之后在运行Docker应用即可,而使用虚拟机我们需要安装虚拟机软件其次在虚拟机软件中安装操作系统,在最终的操作系统在部署服务,这一系列的流程耗时费力

    • 启动迅速节省资源

      如果使用虚拟机的操作系统运行服务,例如MySQL需要向虚拟操作系统申请资源,虚拟操作系统需要向虚拟机申请资源,虚拟机再向物理机器申请资源即大致为 虚拟内存--->虚拟机内存--->物理内存导致虚拟机不但耗费资源而且启动缓慢,然而Docker直接向物理即申请资源 即为虚拟内存--->物理内存的节省资源启动迅速

    对比点 传统虚拟机 Docker容器
    磁盘占用 几个GB到几十个GB左右 几十MB到几百MB左右
    CPU内存占用 虚拟操作系统非常占用CPU和内存 Docker引擎占用极低
    启动速度 (从开机到运行项目)几分钟 (从开启容器到运行项目)几秒
    安装管理 需要专门的运维技术 安装、管理方便
    应用部署 每次部署都费时费力 从第二次部署开始轻松简捷
    耦合性 多个应用服务安装到一起,容易互相影响 每个应用服务一个容器,达成隔离
    系统依赖 需求相同或相似的内核,目前推荐是Linux

    Docker安装配置

    安装

    # 安装依赖
    [root@SR ~]# yum install -y yum-utils device-mapper-persistent-data lvm2	
    
    # 配置国内 docker 的 yum 源(阿里云)
    [root@SR ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
    # 安装 docker-ce
    [root@SR ~]# yum install docker-ce docker-ce-cli containerd.io -y
    	'''
    	注:docker-ce-cli 作用是 docker 命令行工具包
        containerd.io 作用是容器接口相关包
        yum info 软件包的名字,可以查看一个包的具体作用。
    	'''
    # 启动Docker
    [root@SR ~]# systemctl start docker && systemctl enable docker
    
    # 查看docker版本
    [root@SR ~]# docker version
    
    # 查看docker信息
    [root@SR ~]# docker info 
    

    阿里源

    # 由于Docker默认仓库在国外,国外速度网速感人 因此将镜像源修改国内镜像源
    [root@SR ~]#  mkdir -p /etc/docker
    [root@SR ~]#  vim /etc/docker/daemon.json 
            {
              "registry-mirrors": ["https://lz2nib3q.mirror.aliyuncs.com"]
            }
    [root@SR ~]#  systemctl daemon-reload
    [root@SR ~]#  systemctl restart docker
    [root@SR ~]#  docker info
    

    Docker核心概念与架构

    核心概念

    镜像(image)

    • 在我们传统的安装软件的时候需要下载软件的安装包,在Docker中镜像就类似我们的软件安装包,例如我们需要安装MySQL时候需要找到MySQL的安装包,同理我们需要使用Docker运行MySQL服务就需要找到MySQL镜像。
    • 特点: 只读

    容器(container)

    • 当我们下载啦MySQL安装包的时候我们进行安装,进而MySQL的软件包就变成了运行MySQL的程序,在我们找到某软件镜像的时候运行该镜像,该镜像就会成为一个运行某服务的容器 例如我们需要使用Docker跑MySQL服务,当我们将MySQL服务运行就可以变成运行MySQL的容器。
    • 特点: 可读可写

    仓库(repository)

    • 当我们需要使用MySQL镜像的时候,那么这个从哪里找这个镜像呢,在Docker官方给我们提供了仓库地址,在该仓库中存放了所有的Docker镜像,当我们需要获取镜像的时候只需要从仓库地址下载即可
    • 远程仓库:Docker官方提供的存放镜像的仓库
    • 本地仓库:自己本地磁盘存放的Docker镜像

    运行架构图

    d1

    Docker常用命令

    辅助命令

    # 1.安装完成辅助命令
    docker version	--------------------------	查看docker的信息
    docker info		--------------------------	查看更详细的信息
    docker --help	--------------------------	帮助命令
    

    image-20210905181759871

    Image命令

    # 1.查看本机中所有镜像
    	docker images	--------------------------	列出本地所有镜像
    	docker image ls	--------------------------	列出本地所有镜像
    		-a			列出所有镜像(包含中间映像层)
      		-q			只显示镜像id
    

    image-20210905181941948

    # 2.搜索镜像
    	docker search [options] 镜像名	-------------------	去dockerhub上查询当前镜像
    		-s 指定值		列出收藏数不少于指定值的镜像
      		--no-trunc	  显示完整的镜像信息
      	docker search nginx
    

    image-20210905181705928

    # 3.从仓库下载镜像
    	docker pull 镜像名[:TAG|@DIGEST]	----------------- 下载镜像
    		TAG:指定版本
    		@DIGEST:指定摘要
    	docker pull mysql:5.7
    

    image-20210905182323779

    # 4.删除镜像
    	docker rmi 镜像名/镜像ID	--------------------------  删除镜像
    		-f		强制删除
    	docker rmi -f 822
    	
    	# 删除所有镜像
    	docker rm -f $(docker images -aq)
    

    image-20210905182401385

    Container命令

    # 1.运行容器
    	docker run 镜像名	--------------------------	镜像名新建并启动容器
            --name 					    别名为容器起一个名字
            -d							启动守护式容器(在后台启动容器)
            -p 							映射端口号:原始端口号		 指定端口号启动
    
    

    image-20210905182534074

    # 2.查看运行的容器
    	docker ps					--------------------------	列出所有正在运行的容器
            -a			正在运行的和历史运行过的容器
            -q			静默模式,只显示容器编号
    

    image-20210905182622945

    # 3.停止|关闭|重启容器
    	docker start   容器名字或者容器id  --------------- 开启容器
    	docker restart 容器名或者容器id    --------------- 重启容器
    	docker stop  容器名或者容器id 	    ------------------ 正常停止容器运行
    	docker kill  容器名或者容器id      ------------------ 立即停止容器运行
    		stop:优雅退出如果使用该命令会向容器发送信号,容器内部会进行事务等操作
    		kill:直接退出容器内部无任何操作
    

    image-20210905182718576

    # 4.删除容器
    	docker rm -f 容器id和容器名    		--------------------------	强制删除  		
    	docker rm -f $(docker ps -aq)		--------------------------	删除所有容器
    

    image-20210905182804888

    # 7.查看容器的运行日志
    	docker logs [OPTIONS] 容器id或容器名	------------------ 查看容器日志
            -t			 日志显示时间戳
            -f			 实时展示日志
            --tail 	     数字	显示最后多少条
        docker logs -tf --tail 5 c6
    

    image-20210905200049920

    # 5.查看容器内进程
    	docker top 容器id或者容器名 ------------------ 查看容器内的进程
    

    image-20210905213942622

    # 6.查看查看容器内部细节
    	docker inspect 容器id 		------------------ 查看容器内部细节
    

    image-20210905214035507

    # 8.进入容器内部
    	docker exec [options] 容器id 容器内命令 ------------------ 进入容器执行命令
    		-i		以交互模式运行容器,通常与-t一起使用
       		-t		分配一个伪终端    shell窗口   bash 
       		-d		后台运行
        docker exec -it c63 bash
    

    image-20210905214206211

    # 9.容器和宿主机之间复制文件
    	docker cp 文件|目录 容器id:容器路径           -----------------   将宿主机复制到容器内部
    	docker cp 容器id:容器内资源路径 宿主机目录路径  -----------------   将容器内资源拷贝到主机上
    
    

    image-20210905214428319

    # 10.容器打包成新的镜像
    	  docker commit -m "描述信息" -a "作者信息"   (容器id或者名称)打包的镜像名称:标签
    	  
    	  docker commit -m "nginx:1.0" -a "SR" 1e nginx:1.0
    

    image-20210905222120372

    # 11.打包镜像
    		docker save 镜像名 | ID -o  名称.tar
    		
    		docker save 15 -o nginx.tar
    

    image-20210905222345020

    # 12.载入镜像
    		docker load -i   名称.tar
    		docker load -i nginx.tar
    

    image-20210905222626947

    # 13.容器开机自启
    		docker run --restart=always 镜像名称 | ID
    		docker run -d -p 80:80 --restart=always c2
    

    image-20210905223126031

    # 14.数据卷(volum)实现与宿主机共享目录
    docker run -v 宿主机的路径|任意别名:/容器内的路径 镜像名
    	注意: 
    			1.如果是宿主机路径是绝对路径,宿主机目录会覆盖容器内目录内容 如果宿主机器目录不存在会自动创建
    			2.如果是宿主机器是相对路径则会在docker运行容器时自动在宿主机中创建一个目录,并将容器目录文件复制到宿主机中
    			3.容器目录不可以为相对路径必须为绝对路径
    			4.容器内部修改挂载点的权限宿主机器会根据容器内部属主的UID在对应的宿主机更改权限
    			5.容器删除不会影响宿主机挂载的目录
    

    image-20210906091949444

    # 如果是宿主机器是相对路径则会在docker运行容器时自动在宿主机中创建一个目录,并将容器目录文件复制到宿主机中
    docker run -d -v test2:/etc/ nginx:latest --name centos2
    

    image-20210906092417916

    # 容器目录不可以为相对路径必须为绝对路径
    docker run -d -v /root/test3:etc nginx:latest --name centos2
    

    image-20210906092543000

    # 	容器内部修改挂载点的权限宿主机器会根据容器内部属主的UID在对应的宿主机更改权限
    ll -d test4/
    

    image-20210906093502603

    # 容器删除不会影响宿主机挂载的目录
    docker rm -f centos4
    ll 
    

    image-20210906093709929

    # 指定容器名称
    docker run -h (容器名称) 容器镜像 | ID
    docker run -d -p 82:80 --name nginx2 -h nginx2 nginx:latest 
    docker exec -it nginx2 bash
    

    image-20210906163138356

    Docker镜像组成原理

    镜像组成

    在上述中我们可以将镜像看做一个软件包,既然镜像属于软件包那么一个镜像就应该有软件包运行所需要的文件 例如:本省的软件文件,依赖文件,库文件,配置文件,环境变量等。

    镜像体积过大

    在Docker中容器属于操作系用级别隔离,因此运行一个Docker镜像还需要拥有操作系统,最终可以看出一个镜像组成包含操作系统依赖,软件自身依赖,以及软件自身包等,由于这些各种文件依赖等导致虽然Docker轻量然而镜像体积过大。

    imageyl

    联合文件系统

    Union文件系统是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统。而Docker就是使用联合文件系统,在上图中可以看到一个完整的Docker镜像其实是由多个文件系统共同组成对外提供一个文件系统,在Docker镜像之中每个文件系统都被加载,而对外提供的系统是由一个个子文件系统组成而该子文件系统都被加载因此整个外部文件系统所需要的所有文件都被加载。

    Docker分层架构

    在上图中可以看出其实镜像底层都需要操作系统等基础镜像依赖以及一些公共的库,因此我们可以将这些公共的文件进行抽象处理,这样就无需拉取镜像的时候都会拉取一些重复的文件。

    如果我们进行镜像分层,可以实现资源的共享,无需加载一些重复的文件系统,这样下载镜像的时候降低了镜像的大小,运行镜像的时候无需重复运行一些重复的文件系统节省资源。

    unionfsimages

    Docker网络模式

    常用命令

    查看网络信息

    [root@localhost ~]# docker network ls
    

    image-20210906153634444

    创建网桥

    # -d指定网桥网络类型
    [root@localhost ~]# docker network create lnmp -d bridge 
    

    image-20210906153833525

    删除网桥

    [root@localhost ~]# docker network rm lnmp 
    

    image-20210906153942733

    bridge模式

    简介

    当我们运行某些项目的时候,可能需要运行多个容器,在某些情况下我们需要保证容器之间能够进行网络之间的通信。

    当Docker服务被启动的时候,操作系统会自动生成一个网卡 docker0,该网卡物理上属于一块网卡,逻辑上可以看做一个虚拟交换机,当Docker运行容器的时候容器会绑定到该虚拟交换机上,这样通过该虚拟交换机就行成一个二层网络用来容器互联。

    在Docker容器被启动的时候创建主机会创建一对虚拟网卡 veth pair 设备(这一对网卡中其中一个网卡接收的数据,另外一块网卡会接收相同的数据),Docker将 veth pair 网卡其中一块放在Docker容器内部命名为 eth0,另外一块网卡绑定在虚拟交换机上名称以 veth 开头,并且该虚拟交换机会自动给容器分配 IP 地址,容器内部会将网桥的 IP 地址充当网关。

    图解

    networkbriedge

    容器互通

    # 运行两个容器
    [root@localhost ~]# docker run -d -p 80:80 --network lnmp --restart=always --name nginx0 nginx:latest 
    
    [root@localhost ~]# docker run -d -p 81:80 --network lnmp --restart=always --name nginx1 nginx:latest 
    
    # 查看网桥的详细信息
    [root@localhost ~]# docker inspect lnmp 
    

    image-20210906162545034

    # 查看容器ip
    root@1524edfbce9e:~# ifconfig  
    
    # 检测网络连通性
    root@1524edfbce9e:~# ping 172.19.0.2 -c 1
    

    image-20210906163328090

    IP与容器名映射

    虽然网桥为我们容器分配啦 IP地址,但是该地址属于自动分配不是静态的地址,大多数的时候我们需要一个固定的 IP 地址,在Docker中会将容器 IP 地址与容器名称进行映射,当我们访问容器名称的时候就是访问容器的 IP地址,简单粗暴的认为此时容器名称就是容器的 IP地址。

    root@1524edfbce9e:~# ping nginx0 -c 1
        
    root@1524edfbce9e:~# curl nginx0    
    

    image-202109061641085223404

    host模式

    简介

    如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的网络名称空间(Network Namespace),而是和宿主机共用一个网络名称空间(Network Namespace)。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

    使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

    图解

    1725357-20210917110425724-1546711923

    测试

    [root@localhost ~]# docker run -d -p 80:80 -h nginx --name nginx --restart=always --network=host nginx:1.13.12 
    
    # 进入容器
    [root@localhost ~]# docker exec -it nginx bash
    

    551210645

    container模式

    简介

    这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信

    图解

    image-20210917150003376

    测试

    # 由于nginx2与nginx1共用同一网络空间 因此此时不需要做端口映射了
    [root@localhost dockercompose]# docker run --network container:nginx -d  --name nginx2 --restart always nginx:1.13.12 
    

    Docker数据卷

    作用

    在Docker中一般使用容器用来进行计算,通俗点来说数据卷是将容器文件与宿主机文件进行映射实现将容器内的数据保存到宿主机器内,这样不但实现了数据的持久化保存同时实现了数据的共享,当我们操作宿主机器时候会将操作的结果同步到容器内。

    特点

    • 数据卷可以在容器与容器之间进行共享
    • 对数据卷的操作会立马生效
    • 对数据卷的更新不会影响镜像
    • 容器是否存在不会影响数据卷

    常用命令

    创建数据卷

    [root@localhost ~]# docker volume create test 
    

    查看数据卷

    [root@localhost ~]# docker volume ls
    

    image-20210906223929351

    查看详细信息

    [root@localhost ~]# docker volume inspect test 
    

    image-20210906224055529

    删除数据卷

    # 删除指定数据卷
    [root@localhost ~]# docker volume rm test 		
    
    # 删除未使用的数据卷
    [root@localhost ~]# docker volume prune test 
    

    image-20210906224240682

    挂载映射

    # 自动创建挂载目录会在docker默认的挂载目录下生成目录
    [root@localhost ~]# docker run -d -p 80:80 --name nginx0 -h nginx0 -v nginx:/usr/share/nginx/html nginx:latest 
    
    [root@localhost ~]# cd /var/lib/docker/volumes/nginx/_data
    
    # 向挂载点写入数据
    [root@localhost _data]# echo "hello world" > index.html
    

    image-20210907151829821

    # 容器向宿主机器写入数据
    root@nginx0:/usr/share/nginx/html/projectA# echo "hello world" > test.txt
    

    image-20210907152027870

    # 容器只读
    [root@localhost ~]# docker run -d -p 81:80 --name nginx1 -h nginx1 --restart=always -v nginx:/usr/share/nginx/html:ro nginx:latest 
    

    image-20210907153100501

    # 外部访问容器数据
    [root@localhost ~]# curl 172.17.0.2/projectA/index.html
    

    image-20210907152124220

    Docker安装常用服务

    安装mysql

    # 1.拉取mysql镜像到本地
    	docker pull mysql:tag (tag不加默认最新版本)
    	
    # 2.运行mysql服务
    	docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:tag  						  --没有暴露外部端口外部不能连接
    	docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d  mysql:tag  --没有暴露外部端口
    
    # 3.进入mysql容器
    	docker exec -it 容器名称|容器id bash
    
    # 4.外部查看mysql日志
    	docker logs 容器名称|容器id
    
    # 5.使用自定义配置参数
    	docker run --name mysql -v /root/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -d mysql:tag
    
    # 6.将容器数据位置与宿主机位置挂载保证数据安全
    	docker run --name mysql -v /root/mysql/data:/var/lib/mysql -v /root/mysql/conf.d:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -d mysql:tag
    
    # 7.通过其他客户端访问 如在window系统|macos系统使用客户端工具访问
    	
    # 8.将mysql数据库备份为sql文件
    	docker exec mysql|容器id sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /root/all-databases.sql  --导出全部数据
    	docker exec mysql sh -c 'exec mysqldump --databases 库表 -uroot -p"$MYSQL_ROOT_PASSWORD"' > /root/all-databases.sql  --导出指定库数据
    	docker exec mysql sh -c 'exec mysqldump --no-data --databases 库表 -uroot -p"$MYSQL_ROOT_PASSWORD"' > /root/all-databases.sql  --导出指定库数据不要数据
    
    # 9.执行sql文件到mysql中
    	docker exec -i mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /root/xxx.sql
    

    安装Redis服务

    # 1.在docker hub搜索redis镜像
    	docker search redis
    
    # 2.拉取redis镜像到本地
    	docker pull redis
    
    # 3.启动redis服务运行容器
    	docker run --name redis -d redis:tag (没有暴露外部端口)
    	docker run --name redis -p 6379:6379 -d redis:tag (暴露外部宿主机端口为6379进行连接) 
    
    # 4.查看启动日志
    	docker logs -t -f 容器id|容器名称
    
    # 5.进入容器内部查看
    	docker exec -it 容器id|名称 bash  
    
    # 6.加载外部自定义配置启动redis容器
    	默认情况下redis官方镜像中没有redis.conf配置文件 需要去官网下载指定版本的配置文件
    	1. wget http://download.redis.io/releases/redis-5.0.8.tar.gz  下载官方安装包
    	2. 将官方安装包中配置文件进行复制到宿主机指定目录中如 /root/redis/redis.conf文件
    	3. 修改需要自定义的配置
    		 bind 0.0.0.0 开启远程权限
    		 appenonly yes 开启aof持久化
    	4. 加载配置启动
    	docker run --name redis -v /root/redis:/usr/local/etc/redis -p 6379:6379 -d redis redis-server /usr/local/etc/redis/redis.conf  
    
    # 7.将数据目录挂在到本地保证数据安全
    	docker run --name redis -v /root/redis/data:/data -v /root/redis/redis.conf:/usr/local/etc/redis/redis.conf -p 6379:6379 -d redis redis-server 					/usr/local/etc/redis/redis.conf  
    

    安装Nginx

    # 1.在docker hub搜索nginx
    	docker search nginx
    
    # 2.拉取nginx镜像到本地
    	[root@localhost ~]# docker pull nginx
        Using default tag: latest
        latest: Pulling from library/nginx
        afb6ec6fdc1c: Pull complete 
        b90c53a0b692: Pull complete 
        11fa52a0fdc0: Pull complete 
        Digest: sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
        Status: Downloaded newer image for nginx:latest
        docker.io/library/nginx:latest
    
    # 3.启动nginx容器
    		docker run -p 80:80 --name nginx01 -d nginx
    
    # 4.进入容器
    		docker exec -it nginx01 /bin/bash
    		查找目录:  whereis nginx
    		配置文件:  /etc/nginx/nginx.conf
    
    # 5.复制配置文件到宿主机
    		docker cp nginx01(容器id|容器名称):/etc/nginx/nginx.conf 宿主机名录
    
    # 6.挂在nginx配置以及html到宿主机外部
    		docker run --name nginx02 -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf -v /root/nginx/html:/usr/share/nginx/html -p 80:80 -d nginx		
    

    安装Tomcat

    # 1.在docker hub搜索tomcat
    	docker search tomcat
    
    # 2.下载tomcat镜像
    	docker pull tomcat
    
    # 3.运行tomcat镜像
    	docker run -p 8080:8080 -d --name mytomcat tomcat
    
    # 4.进入tomcat容器
    	docker exec -it mytomcat /bin/bash
    
    # 5.将webapps目录挂载在外部
    	docker run -p 8080:8080 -v /root/webapps:/usr/local/tomcat/webapps -d --name mytomcat tomcat
    
    

    安装MongoDB数据库

    # 1.运行mongDB
    	docker run -d -p 27017:27017 --name mymongo mongo  ---无须权限
    	docker logs -f mymongo --查看mongo运行日志
    
    # 2.进入mongodb容器
    	docker exec -it mymongo /bin/bash
    		直接执行mongo命令进行操作
    
    # 3.常见具有权限的容器
    	docker run --name  mymongo  -p 27017:27017  -d mongo --auth
    
    # 4.进入容器配置用户名密码
    	mongo
    	use admin 选择admin库
    	db.createUser({user:"root",pwd:"root",roles:[{role:'root',db:'admin'}]})   //创建用户,此用户创建成功,则后续操作都需要用户认证
    	exit
    
    # 5.将mongoDB中数据目录映射到宿主机中
    	docker run -d -p 27017:27017 -v /root/mongo/data:/data/db --name mymongo mongo 
    

    安装ElasticSearch

    • 注意:调高JVM线程数限制数量

    拉取镜像运行elasticsearch

    # 1.dockerhub 拉取镜像
    	docker pull elasticsearch:6.4.2
    # 2.查看docker镜像
    	docker images
    # 3.运行docker镜像
    	docker run -p 9200:9200 -p 9300:9300 elasticsearch:6.4.2
    
    • 启动出现如下错误
    • image-20200602184321790

    预先配置

    # 1.在centos虚拟机中,修改配置sysctl.conf
    	vim /etc/sysctl.conf
    # 2.加入如下配置
    	vm.max_map_count=262144 
    # 3.启用配置
    	sysctl -p
    	注:这一步是为了防止启动容器时,报出如下错误:
    	bootstrap checks failed max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
    
    

    启动EleasticSearch容器

    # 0.复制容器中data目录到宿主机中
    	docker cp 容器id:/usr/share/share/elasticsearch/data /root/es
    # 1.运行ES容器 指定jvm内存大小并指定ik分词器位置
    	docker run -d --name es -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms128m -Xmx128m" -v /root/es/plugins:/usr/share/elasticsearch/plugins -v /root/es/data:/usr/share/elasticsearch/data elasticsearch:6.4.2
    

    安装IK分词器

    # 1.下载对应版本的IK分词器
    	wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.4.2/elasticsearch-analysis-ik-6.4.2.zip
    
    # 2.解压到plugins文件夹中
    	yum install -y unzip
    	unzip -d ik elasticsearch-analysis-ik-6.4.2.zip
    
    # 3.添加自定义扩展词和停用词
    	cd plugins/elasticsearch/config
    	vim IKAnalyzer.cfg.xml
    	<properties>
    		<comment>IK Analyzer 扩展配置</comment>
    		<!--用户可以在这里配置自己的扩展字典 -->
    		<entry key="ext_dict">ext_dict.dic</entry>
    		<!--用户可以在这里配置自己的扩展停止词字典-->
    		<entry key="ext_stopwords">ext_stopwords.dic</entry>
    	</properties>
    
    # 4.在ik分词器目录下config目录中创建ext_dict.dic文件   编码一定要为UTF-8才能生效
    	vim ext_dict.dic 加入扩展词即可
    # 5. 在ik分词器目录下config目录中创建ext_stopword.dic文件 
    	vim ext_stopwords.dic 加入停用词即可
    
    # 6.重启容器生效
    	docker restart 容器id
    # 7.将此容器提交成为一个新的镜像
    	docker commit -a="xiaochen" -m="es with IKAnalyzer" 容器id xiaochen/elasticsearch:6.4.2
    

    安装Kibana

    # 1.下载kibana镜像到本地
    	docker pull kibana:6.4.2
    
    # 2.启动kibana容器
    	docker run -d --name kibana -e ELASTICSEARCH_URL=http://10.15.0.3:9200 -p 5601:5601 kibana:6.4.2
    

    Dockerfile

    简介

    Dockerfile内部是由一系列的指令组成,可以类似看成一个脚本,当运行Dockerfile文件可以帮我们生成一个自定义的镜像

    hxjg1

    自定义镜像

    我们可以根据自己的业务专门制作专属的镜像,同时可以将自己的应用打包制作成镜像,后期我们进行项目迁移,或者多台服务器运行该应用我们只需要运行该镜像即可,真正的做到了一次制作,终身使用。

    Dockerfile运行解析

    宿主机在某目录下创建 Dockerfile 文件,包含该 Dockerfile 的目录被称之为上下文目录,在 Dockerfile 目录下写入构建镜像的指令,当 Dockerfile文件书写完毕之后执行 Docker build 命令, Docker会将 Dockerfile 所在的上下文目录发送给 Docker 服务端,服务端解析 Dockerfile 文件中的指令,执行一条指令会生成一个镜像文件,并且将生成的镜像文件存放在 Docker Cache 中,最终所有的镜像组合成一个最终的镜像暴露给外部用户。

    dockerfilerun

    Dockerfile命令简介

    保留字 作用
    FROM 当前镜像是基于哪个镜像的
    MAINTAINER 镜像维护者的姓名和邮箱地址(已经启用无需再写)
    RUN 构建镜像时需要运行的指令:例如运行mysql 需要使用mysql -u root - p
    EXPOS 当前容器对外暴露出的端口号:方便宿主机器与容器映射**
    WORKDIR 指定在创建容器后,终端默认登录进来的工作目录,一个落脚点
    ENV 用来在构建镜像过程中设置环境变量:例如mysql的MYSQL_ROOT_PASSWORD
    ADD 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar包
    COPY 类似于ADD,拷贝文件和目录到镜像中
    将从构建上下文目录中<原路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
    VOLUME 容器数据卷,用于数据保存和持久化工作
    CMD 指定一个容器启动时要运行的命令
    Dockerfile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run之后的参数替换
    ENTRYPOINT 指定一个容器启动时要运行的命令
    ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及其参数

    官方说明

    Dockerfile命令详解

    FROM

    • 基于那个镜像进行构建新的镜像,在构建时会自动从docker hub拉取base镜像 必须作为Dockerfile的第一个指令出现
    • 语法:
    FROM  <image>
    FROM  <image>[:<tag>]     使用版本不写为latest
    FROM  <image>[@<digest>]  使用摘要
    
    [root@localhost dockerfile]# vim Dockerfile
            # 基于centos镜像
            FROM centos:7
    
    # 构建上下文生成镜像
    [root@localhost dockerfile]# docker build -t mycentos7:01 ./
    

    image-20210908104852891

    MAINTAINER

    • 镜像维护者的姓名和邮箱地址[废弃]
    • 语法:
    MAINTAINER <name>
    

    RUN

    • RUN指令将在当前映像之上的新层中执行任何命令并提交结果。生成的提交映像将用于Dockerfile中的下一步

    • 语法:

    RUN ["executable", "param1", "param2"] (exec form)
    RUN ["/bin/bash", "-c", "echo hello"]
    
    [root@localhost dockerfile]# vim Dockerfile
            # 基于centos镜像
            FROM centos:7
            # 给新镜像添加vim命令
            RUN yum -y install vim
    
    # 构建上下文生成镜像
    [root@localhost dockerfile]# docker build -t mycentos7:02 ./
    

    image-20210908105842708

    EXPOSE

    • 用来指定构建的镜像在运行为容器时对外暴露的端口
    • 语法:
    EXPOSE 80/tcp  如果没有显示指定则默认暴露都是tcp
    EXPOSE 80/udp
    
    [root@localhost dockerfile]# vim Dockerfile 
    	FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
      
    [root@localhost dockerfile]# docker build -t mycentos7:03 ./
    
    [root@localhost dockerfile]# docker run -p 80:80 mycentos7:03 
    

    image-20210908110147218

    WORKDIR

    • 用来为Dockerfile中的任何RUN、CMD、ENTRYPOINT、COPY和ADD指令设置工作目录。如果WORKDIR不存在,即使它没有在任何后续Dockerfile指令中使用,它也将被创建。
    • 语法:
    WORKDIR /path/to/workdir
    
    # 注意:WORKDIR指令可以在Dockerfile中多次使用。如果提供了相对路径,则该路径将与先前WORKDIR指令的路径相对
    WORKDIR /a
    WORKDIR b
    WORKDIR c
    
    [root@localhost dockerfile]# vim Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        # 配置工作路径	
        WORKDIR /path/test
    [root@localhost dockerfile]# docker build -t mycentos7:04 ./
    

    image-20210908110355581

    COPY

    • 用来将context目录中指定文件复制到镜像的指定目录中

    • 语法:

    COPY src dest
    COPY ["<src>",... "<dest>"]
    
    [root@localhost dockerfile]# cat Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        WORKDIR /path/test
        # 将a.txt文件复制到/path/test中
        COPY a.txt /path/test
    
    [root@localhost dockerfile]# docker build -t mycentos7:05 ./
    

    image-20210908140406012

    ADD

    • 用来从context上下文复制新文件、目录或远程文件url,并将它们添加到位于指定路径的映像文件系统中,如果是压缩包在镜像中会自动解压。

    • 语法:

    ADD hom* /mydir/       通配符添加多个文件
    ADD hom?.txt /mydir/   通配符添加
    ADD test.txt relativeDir/  可以指定相对路径
    ADD test.txt /absoluteDir/ 也可以指定绝对路径
    ADD url 
    
    [root@localhost dockerfile]# cat Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        WORKDIR /path/test
        # 将a.txt文件复制到/path/test中
        COPY a.txt /path/test
        # 复制b.txt到/path/test中
        ADD b.txt /path/test
        # 复制url到指定目录下
    	ADD https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.70/bin/apache-tomcat-8.5.70-fulldocs.tar.gz /path/test/download
    
    [root@localhost dockerfile]# docker build -t mycentos7:06 ./
    

    image-20210908143746614

    [root@localhost dockerfile]# vim Dockerfile 
    	FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        WORKDIR /path/test
        COPY a.txt /path/test
        ADD b.txt /path/test
        # 复制压缩包到指定目录在容器内部会被自动解压
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz /path/test
    [root@localhost dockerfile]# docker build -t mycentos7:08 ./
    

    image-20210908144201926

    VOLUME

    • 用来定义容器运行时可以挂在到宿主机的目录
    • 语法:
    VOLUME ["/path1","path2"]
    VOLUME /path
    
    [root@localhost dockerfile]# vim Dockerfile 
    	FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        WORKDIR /path/test
        COPY a.txt /path/test
        ADD b.txt /path/test
        # 复制压缩包到指定目录在容器内部会被自动解压
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz /path/test
        VOLUME /path/test
    
    [root@localhost dockerfile]# docker build -t mycentos7:10 ./
    
    [root@localhost dockerfile]# docker run -itd --restart=always -v /path/test:/path/test mycentos7:10
    
    [root@localhost dockerfile]# echo mysql hostos path is /path/tes > /path/test/test.txt
    

    image-20210908152814717

    ENV

    • 用来为构建镜像设置环境变量。这个值将出现在构建阶段中所有后续指令的环境中。

    • 语法:

    ENV <key> <value>
    ENV <key>=<value> ...
    
    [root@localhost dockerfile]# vim Dockerfile 
    	FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        RUN mkdir -p /path/test
        
        # 将/path/test设置成环境变量
        ENV BASE_DIR /path/test
        # 调用环境变量BASE_DIR
        WORKDIR $BASE_DIR
        COPY a.txt $BASE_DIR
        ADD b.txt $BASE_DIR
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz $BASE_DIR
        VOLUME $BASE_DIR
    [root@localhost dockerfile]# docker build -t mycentos7:13 .
    

    image-20210908162653612

    CMD 命令

    • 用来为启动的容器指定执行的命令,在Dockerfile中只能有一条CMD指令。如果列出多个命令,则只有最后一个命令才会生效。
    • 如果我们在运行容器的时候给CMD传入命令,则默认的命令会被传入的命令覆盖
    • 语法:
    CMD ["executable","param1","param2"] (exec form, this is the preferred form)
    CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
    CMD command param1 param2 (shell form)
    
    [root@localhost dockerfile]# vim Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        RUN mkdir -p /path/test
        ENV BASE_DIR /path/test
        WORKDIR $BASE_DIR
        COPY a.txt $BASE_DIR
        ADD b.txt $BASE_DIR
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz $BASE_DIR
        VOLUME $BASE_DIR
    [root@localhost dockerfile]# docker build -t mycentos7:14
    

    image-20210908165733738

    [root@localhost dockerfile]# vim Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        RUN mkdir -p /path/test
        ENV BASE_DIR /path/test
        WORKDIR $BASE_DIR
        COPY a.txt $BASE_DIR
        ADD b.txt $BASE_DIR
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz $BASE_DIR
        VOLUME $BASE_DIR
        # 启动查看目录
        CMD ls $BASE_DIR
    [root@localhost dockerfile]# docker build -t mycentos7:17
    

    image-20210908170237542

    [root@localhost dockerfile]# docker run -it mycentos7:17 ls /path/test
    

    image-20210908170512178

    ENTRYPOINT

    • 用来为启动的容器指定执行的命令,当有多个命令的时候其只执行最后一条命令
    • 默认情况下如果我们我们在运行容器的时候给ENTRYPOINT传入命令其不会覆盖原有指令
    • 语法:
    ["executable", "param1", "param2"]
    ENTRYPOINT command param1 param2
    
    [root@localhost dockerfile]# vim Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        RUN mkdir -p /path/test
        ENV BASE_DIR /path/test
        WORKDIR $BASE_DIR
        COPY a.txt $BASE_DIR
        ADD b.txt $BASE_DIR
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz $BASE_DIR
        VOLUME $BASE_DIR
        ENTRYPOINT ls $BASE_DIR
        # 只会执行最后一条
        ENTRYPOINT echo "hello world"
    [root@localhost dockerfile]# docker build -t mycentos7:19
    

    image-20210908204335061

    # entrypoint默认情况下该命令不会被覆盖
    [root@localhost dockerfile]# docker run -it mycentos7:19 ls /path/test
    

    image-20210908210723915

    # 添加entrypoint参数覆盖指定命令
    [root@localhost dockerfile]# docker run -it --entrypoint=ls mycentos7:19 /path/test
    

    image-20210908212417453

    CMD与ENTRYPOINT共用

    ENTRYPOINT指令,往往用于设置容器启动后的第一个命令,这对一个容器来说往往是固定的。CMD指令,往往用于设置容器启动的第一个命令的默认参数,这对一个容器来说可以是变化的。

    [root@localhost dockerfile]# vim Dockerfile 
        FROM centos:7
        RUN yum -y install vim
        EXPOSE 80/tcp
        EXPOSE 80/udp
        RUN mkdir -p /path/test
        ENV BASE_DIR /path/test
        WORKDIR $BASE_DIR
        COPY a.txt $BASE_DIR
        ADD b.txt $BASE_DIR
        ADD apache-tomcat-8.5.70-fulldocs.tar.gz $BASE_DIR
        VOLUME $BASE_DIR
        CMD ["echo test cmd argument"]
        ENTRYPOINT ["echo"]
        
    [root@localhost dockerfile]# docker build -t mycentos7:27 .
    
    # 此时CMD会以参数的形式传递给ENTRYPOINT 在运行的时候没有传入参数会以默认参数
    [rootvim@localhost dockerfile]# docker run -it mycentos7:27
    

    image-20210908215432843

    # 手动传入会覆盖默认参数
    [root@localhost dockerfile]# docker run -it mycentos7:27 hello world
    

    image-20210908215511511

    Dockerfile构建Django

    [root@localhost dockerfile]# vim Dockerfile 
      #指定基础镜像
      FROM python:3.6.12
      RUN pip3 install django==1.11.11 -i https://pypi.douban.com/simple/
      # 创建Django项目
      RUN django-admin startproject app
      # 配置工作目录
      WORKDIR /app
      # 暴露外部端口
      EXPOSE 8000
      # 启动服务
      ENTRYPOINT ["python3","manage.py","runserver"]
      # 当作参数
      CMD [""]
    
    # 构建镜像
    [root@localhost dockerfile]# docker build -t demo:01 .
    
    # 启动镜像 0.0.0.0:8000会被CMD以参数的形式传递给ENTRYPOINT
    root@localhost test]# docker run -d -p 8000:8000 --name demo1 --restart=always demo:01 0.0.0.0:8000
    

    image-20210910235021475

    Docker-compose

    简介

    Docker-compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。所谓容器编排即是按照一种指定顺序对相应的容器启动。

    在上述中使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。

    Docker-compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器为一个项目(project)。

    Docker-compose 中有两个重要的概念:

    • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
    • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

    项目地址

    安装

    # 下载二进制文件
    [root@localhost dockerfile]# curl -L https://github.com/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
    
    # 添加执行权限
    [root@localhost dockerfile]# chmod +x /usr/local/bin/docker-compose
    
    # 查询是否安装成功
    [root@localhost ~]# docker-compose -v
    

    image-20210914161442690

    简单使用

    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"  # 项目版本
        services:
          nginx:       # 服务名称
            image: nginx       # 当前服务所使用的镜像
            container_name: nginx       # 容器名称      
            ports:
              - 80:80           # 映射端口
     # 运行       
    [root@localhost ~]# docker-compose up
    

    模板文件命令

    image

    指定为镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。

    # 语法
    image: ubuntu
    image: orchardup/postgresql
    image: a4bc65fd
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"  # 项目版本
        services:
          nginx:       # 服务名称
            image: nginx       # 当前服务所使用的镜像不指定tag默认为最新的   
            
      # 运行       
    [root@localhost ~]# docker-compose up
    
    [root@localhost ~]# docker images 
    

    image-20210914201226415

    ports

    暴露端口信息。使用宿主端口:容器端口 (HOST:CONTAINER) 格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。

    '''
    当使用 `HOST:CONTAINER` 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 `YAML` 会自动解析 `xx:yy` 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。
    '''
    # 语法
    ports:
     - "3000"
     - "8000:8000"
     - "49100:22"
     - "127.0.0.1:8001:8001"
        
    [root@localhost dockercompose]# vim docker-compose.yml 
       version: "3.0"
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
      # 运行       
    [root@localhost ~]# docker-compose up       
    [root@localhost ~]# docker ps
    

    image-20210914203801970

    networks

    配置容器连接的网络。

    # 语法
    networks:
    	# 网络名称 如果只是这样定义需要手动创建网络
         - some-network
         - other-network
    # 自动创建上述网桥
    networks:
      some-network:
      other-network:
      
    [root@localhost dockercompose]# cat docker-compose.yml 
    	version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
              
        networks: 
          test:
      # 运行       
    [root@localhost ~]# docker-compose up
    
    [root@localhost dockercompose]# docker network ls
    

    image-20210914204853760

    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
    [root@localhost dockercompose]# docker-compose up
    

    image-20210914205841669

    # 创建网桥
    [root@localhost dockercompose]# docker network create test
    
    [root@localhost dockercompose]# docker-compose up
    
    # 查看详情
    [root@localhost dockercompose]# docker inspect dockercompose_tomcat_1 
    

    image-20210914210314508

    # 自定义网络
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3"
        services:
          nginx:
           image: tomcat:8.0-jre8
           container_name: tomcat
           networks:
             test:
              # 指定容器ip地址
              ipv4_address: 172.66.0.2
    
        networks:
          test:
           ipam:
             config:
             # 配置网段
             - subnet: 172.66.0.0/16
               # 配置网关
               gateway: 172.66.0.1
    
    [root@localhost dockercompose]# docker inspect tomcat
    

    image-20210914232706724

    container_name

    配置容器运行名称

    # 语法
    container_name: 容器名称       # 容器名称      
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat	# 配置容器名称
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
            
    [root@localhost dockercompose]# docker-compose up
    
    [root@localhost dockercompose]# docker ps
    

    image-20210914211508754

    hostname

    配置容器运行内部名称

    # 语法
    hostname: 容器名称
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat	# 配置容器名称
            hostname: tomcat
    
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
            
    [root@localhost dockercompose]# docker exec -it tomcat bash
    
    root@tomcat:/usr/local/tomcat# cat /etc/hostname 
    

    image-20210914211803776

    restart

    配置容器开机自启动

    # 语法
    restart: always
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat	# 配置容器名称
            hostname: tomcat
            restart: always
    
    
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
    

    image-20210914212948549

    working_dir

    配置进入容器所处目录

    # 语法
    restart: path
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat	# 配置容器名称
            hostname: tomcat
            restart: always
            working_dir: /root/test
    
    
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
    

    image-20210914213135808

    volumes

    数据卷所挂载路径设置。可以设置为宿主机路径(HOST:CONTAINER)或者数据卷名称(VOLUME:CONTAINER),并且可以设置访问模式 (HOST:CONTAINER:ro)。

    # 语法
    volumes:
     - /var/lib/mysql
     - cache/:/tmp/cache
     - ~/configs:/etc/configs/:ro
     
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat
    
            hostname: tomcat
    
            restart: always
    
            working_dir: /root/test
    
            volumes: 
              - /root/test:/root/test   
          
    networks: 
      test:
        external:  # 使用指定网络名称
          true  # 如果为true网桥必须先创建
    
        # 写入数据
    [root@localhost dockercompose]# echo "hello world" > /root/test/test.txt
    [root@localhost dockercompose]# docker exec -it tomcat bash
    root@tomcat:~/test# cat test.txt 
    
    

    image-20210914214158543

    [root@localhost dockercompose]# vim docker-compose.yml 
    
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat
    
            hostname: tomcat
    
            restart: always
    
            working_dir: /root/test
    
            volumes: 
              - /root/test:/root/test
              # 使用相对路径进行映射 必须需要声明
              - tomcat01:/usr/local/tomcat/webapps
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
    

    image-20210914214712081

    [root@localhost dockercompose]# vim docker-compose.yml 
    
        # 声明数据卷
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat
    
            hostname: tomcat
    
            restart: always
    
            working_dir: /root/test
    
            volumes: 
              - /root/test:/root/test
              # 使用相对路径进行映射
              - tomcat01:/usr/local/tomcat/webapp
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
            
        volumes: 
    	  # 声明数据卷
          tomcat01:
                
    [root@localhost dockercompose]# docker volume ls 
    

    image-20210914220035786

    [root@localhost dockercompose]# vim docker-compose.yml 
    
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat
    
            hostname: tomcat
    
            restart: always
    
            working_dir: /root/test
    
            volumes: 
              - /root/test:/root/test
              # 使用相对路径进行映射
              - tomcat01:/usr/local/tomcat/webapps
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
    
        volumes: 
    	 # 使用此种方式必须先声明数据卷
          tomcat01:
            # 使用指定数据卷名称
            external: 
              true
    [root@localhost dockercompose]# docker volume inspect tomcat01 
    

    image-20210914220908555

    environment

    设置环境变量。你可以使用数组或字典两种格式。

    只给定名称的变量会自动获取运行 Compose 主机上对应变量的值,可以用来防止泄露不必要的数据。

    # 语法
    environment:
      RACK_ENV: development
      SESSION_SECRET:
    
    environment:
      - RACK_ENV=development
      - SESSION_SECRET
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3.0"
    
        services: 
          tomcat:
            image: tomcat:8.0-jre8
            ports: 
              - "8080:8080"
            networks: 
              - test
            container_name: tomcat
    
            hostname: tomcat
    
            restart: always
    
            working_dir: /root/test
    
            volumes: 
              - /root/test:/root/test
              # 使用相对路径进行映射
              - tomcat01:/usr/local/tomcat/webapps
    
          mysql:
            image: mysql:5.7.31
            # 配置环境变量
            environment: 
              - MYSQL_ROOT_PASSWORD=root
    
            ports: 
              - "3306:3306"
    
        networks: 
          test:
            external:  # 使用指定网络名称
              true  # 如果为true网桥必须先创建
    
        volumes: 
          tomcat01:
            external: 
              true
    $ mysql -uroot -proot -h10.1.1.2 
    

    image-20210914222059382

    env_file

    从文件中获取环境变量,可以为单独的文件路径或列表。

    如果通过 docker-compose -f FILE 方式来指定 Compose 模板文件,则 env_file 中变量的路径会基于模板文件路径。

    如果有变量名称与 environment 指令冲突,则按照惯例,以后者为准。

    # 语法
    env_file: .env
    
    env_file:
      - ./common.env
      - ./apps/web.env
      - /opt/secrets.env
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3"
        services:
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
    
           networks:
             test:
              ipv4_address: 172.66.0.2
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           working_dir: /var/lib/mysql
           env_file:
            # 写配置文件路径
             - ./mysqlconfig.env
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes:
          tomcat01:
            external: true
          mysqlconf:
          mysqldata:
          redisdata:
    $ mysql -uroot -proot -h10.1.1.2
    

    image-20210915205730898

    command

    覆盖容器启动后默认执行的命令。

    # 语法
    command: "执行命令"
        
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3"
        services:
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
    
           networks:
             test:
              ipv4_address: 172.66.0.2
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           environment:
             - MYSQL_ROOT_PASSWORD=root
           working_dir: /var/lib/mysql
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes: 
    
          tomcat01:
            external: true
    
          mysqlconf:
          mysqldata:
          redisdata:
    
    # 远程连接redis
    $ redis-cli -h 10.1.1.2
    	# 写入数据
    	10.1.1.2:6379> set namq SR
    
    # 查看数据
    [root@localhost _data]# cat appendonly.aof 
    

    image-20210914224201756

    depends_on

    解决容器的依赖、启动先后的问题。以下例子中会先启动 redis 再启动 mysql

    # 语法
    
    depends_on:
      # 服务名称
      - mysql
      - redis
    
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3"
        services:
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
           depends_on:
            # 填写服务名称
             - mysql
             - redis
           networks:
             test:
              ipv4_address: 172.66.0.2
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           working_dir: /var/lib/mysql
           env_file:
             - ./mysqlconfig.env
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
    
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes:
          tomcat01:
            external: true
          mysqlconf:
          mysqldata:
          redisdata:
    
    

    healthcheck

    通过命令检查容器是否健康运行。

    # 语法
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 1m30s
      timeout: 10s
      retries: 3
    
    [root@localhost dockercompose]# cat docker-compose.yml 
        version: "3"
        services:
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
           depends_on:
             - mysql
             - redis
           networks:
             test:
              ipv4_address: 172.66.0.2
           healthcheck:
             test: [ "CMD", "curl", "-f", "http://localhost" ]
             interval: 1m30s
             timeout: 10s
             retries: 3
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           working_dir: /var/lib/mysql
           env_file:
             - ./mysqlconfig.env
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes:
          tomcat01:
            external: true
          mysqlconf:
          mysqldata:
          redisdata:
    
    

    sysctls

    配置容器内核参数。

    # 语法
    sysctls:
      net.core.somaxconn: 1024
      net.ipv4.tcp_syncookies: 0
    
    sysctls:
      - net.core.somaxconn=1024
      - net.ipv4.tcp_syncookies=0
        
    [root@localhost dockercompose]# cat docker-compose.yml 
        version: "3"
        services:
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
           depends_on:
             - mysql
             - redis
           networks:
             test:
              ipv4_address: 172.66.0.2
           healthcheck:
             test: [ "CMD", "curl", "-f", "http://localhost" ]
             interval: 1m30s
             timeout: 10s
             retries: 3
           sysctls:
             net.core.somaxconn: 1024
             net.ipv4.tcp_syncookies: 0
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           working_dir: /var/lib/mysql
           env_file:
             - ./mysqlconfig.env
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes:
          tomcat01:
            external: true
          mysqlconf:
          mysqldata:
          redisdata:
    
    

    ulimits

    指定容器的 ulimits 限制值。

    例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制) 和 40000(系统硬限制,只能 root 用户提高)。

    # 语法
      ulimits:
        nproc: 65535
        nofile:
          soft: 20000
          hard: 40000
            
    [root@localhost dockercompose]# cat docker-compose.yml 
        version: "3"
        services:
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
           depends_on:
             - mysql
             - redis
           networks:
             test:
              ipv4_address: 172.66.0.2
           healthcheck:
             test: [ "CMD", "curl", "-f", "http://localhost" ]
             interval: 1m30s
             timeout: 10s
             retries: 3
           sysctls:
             net.core.somaxconn: 1024
             net.ipv4.tcp_syncookies: 0
           ulimits:
            nproc: 65535
            nofile:
              soft: 20000
              hard: 40000
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           working_dir: /var/lib/mysql
           env_file:
             - ./mysqlconfig.env
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes:
          tomcat01:
            external: true
          mysqlconf:
          mysqldata:
          redisdata:
    
    

    build

    指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。 Compose 将会利用它自动构建这个镜像,然后使用这个镜像。

    # 语法
    version: '3'
    services:
    
      webapp:
        build:
          # 指定dockerfile上下文目录
          context: ./dir
          # dockerfile文件
          dockerfile: Dockerfile
          # 构建镜像时候变量
          args:
            buildno: 1
                
    [root@localhost dockercompose]# vim docker-compose.yml 
        version: "3"
        services:
          django:
            build:
              # dockerfile上下文目录路径
              context: ./dockerfile
              # dockerfile文件
              dockerfile: Dockerfile
            container_name: django
            hostname: django
            ports:
            - "8000:8000"
            restart: always
            depends_on:
              - mysql
              - redis
            networks:
              test:
               ipv4_address: 172.66.0.5
          tomcat:
           image: tomcat:8.0-jre8
           container_name: tomcat
           hostname: tomcat
           restart: always
           working_dir: /root/test
           ports: 
            - "8080:8080"
           volumes: 
             - /root/test:/root/test
            # 使用相对路径进行映射
             - tomcat01:/usr/local/tomcat/webapps
           depends_on:
             - mysql
             - redis
           networks:
             test:
              ipv4_address: 172.66.0.2
           healthcheck:
             test: [ "CMD", "curl", "-f", "http://localhost" ]
             interval: 1m30s
             timeout: 10s
             retries: 3
          mysql:
           image: mysql:5.7.31
           container_name: mysql
           hostname: mysql
           restart: always
           working_dir: /var/lib/mysql
           env_file:
             - ./mysqlconfig.env
           ports: 
            - "3306:3306"
           volumes: 
            - mysqldata:/var/lib/mysql
            - mysqlconf:/etc/mysql
           networks:
             test:
              ipv4_address: 172.66.0.3 
    
          redis:
           image: redis:5.0.10
           container_name: redis
           hostname: redis
           restart: always
           working_dir: /data
           ports: 
            - "6379:6379"
           volumes: 
            - redisdata:/data
           networks: 
             test:
              ipv4_address: 172.66.0.4
           command: "redis-server --appendonly yes"
    
        networks:
          test:
           ipam:
             config:
             - subnet: 172.66.0.0/16
               gateway: 172.66.0.1
    
        volumes:
          tomcat01:
            external: true
          mysqlconf:
          mysqldata:
          redisdata:
    

    image-20210915232935141

    docker-compose常用命令

    命令对象与格式

    对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。

    执行 docker-compose [COMMAND] --help 或者 docker-compose help [COMMAND] 可以查看具体某个命令的使用格式。

    docker-compose 命令的基本的使用格式是

    docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
    

    命令选项

    • -f, --file FILE 指定使用的 Compose 模板文件,默认为 docker-compose.yml,可以多次指定。
    • -p, --project-name NAME 指定项目名称,默认将使用所在目录名称作为项目名。
    • --x-networking 使用 Docker 的可拔插网络后端特性
    • --x-network-driver DRIVER 指定网络后端的驱动,默认为 bridge
    • --verbose 输出更多调试信息。
    • -v, --version 打印版本并退出。

    命令使用案例

    up

    格式为 docker-compose up [options] [SERVICE...]

    • 该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。

    • 链接的服务都将会被自动启动,除非已经处于运行状态。

    • 可以说,大部分时候都可以直接通过该命令来启动一个项目。

    • 默认情况,docker-compose up 启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试。

    • 当通过 Ctrl-C 停止命令时,所有容器将会停止。

    • 如果使用 docker-compose up -d,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项。

    • 默认情况,如果服务容器已经存在,docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml 文件的最新内容

    # 后台启动
    [root@localhost dockercompose]# docker-compose up -d
    

    image-20210916150304030

    down`
    • 此命令将会停止 up 命令所启动的容器,并移除网络
    [root@localhost dockercompose]# docker-compose down 
    

    image-20210916150405620

    exec
    • 进入指定的容器。
    # exec后跟服务名称
    [root@localhost dockercompose]# docker-compose exec redis bash
    

    image-20210916150554867

    ps
    • 列出项目中目前的所有容器。
    [root@localhost dockercompose]# docker-compose ps
    

    image-20210916150659060

    rm

    删除所有(停止状态的)服务容器。推荐先执行 docker-compose stop 命令来停止容器。

    选项:

    • -f, --force 强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项。
    • -v 删除容器所挂载的数据卷。
    [root@localhost dockercompose]# docker-compose stop tomcat
    
    [root@localhost dockercompose]# docker-compose rm -f tomcat
    
    [root@localhost dockercompose]# docker-compose ps
    

    image-20210916150926726

    top
    • 查看各个服务容器内运行的进程。
    [root@localhost dockercompose]# docker-compose top
    

    image-20210916151115509

    pause
    • 将运行的容器暂停
    [root@localhost dockercompose]# docker-compose pause redis
    
    [root@localhost dockercompose]# docker-compose ps redis
    

    image-20210916151352789

    unpause
    • 恢复处于暂停状态中的服务
    [root@localhost dockercompose]# docker-compose unpause redis
    
    [root@localhost dockercompose]# docker-compose ps redis
    

    image-20210916151515135

    stop

    停止已经处于运行状态的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。

    选项:

    • -t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。
    [root@localhost dockercompose]# docker-compose stop redis
    
    [root@localhost dockercompose]# docker-compose ps redis
    

    image-20210916151703527

    start
    • 启动已经存在的服务容器。
    [root@localhost dockercompose]# docker-compose start redis
    
    [root@localhost dockercompose]# docker-compose ps redis
    

    image-20210916151822021

    restart

    格式为 docker-compose restart [options] [SERVICE...]

    重启项目中的服务。

    选项:

    • -t, --timeout TIMEOUT 指定重启前停止容器的超时(默认为 10 秒)。

    Docker可视化工具

    安装Portainer

    [root@localhost ~]# docker pull  portainer/portainer
    
    [root@localhost ~]# docker volume create portainer_data
    
    '''
    1:Portainer内部端口8000 web界面端口9000 
    2:需要与docker引擎通信 因此需要映射scok文件
    '''
    [root@localhost ~]#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
    

    image-20210916153503233

  • 相关阅读:
    每天一道Java题[4]
    每天一道Java题[3]
    每天一道Java题[2]
    关于OOCSS架构
    新blog开张!
    [原]C++拾遗
    mark
    今天的情况(也是10月份的总结)
    11月份的总结
    Linux管道编程实例
  • 原文地址:https://www.cnblogs.com/SR-Program/p/15306686.html
Copyright © 2011-2022 走看看