Hello World

Your description here.

Docker笔记

默认分类 4 评

image-20200828221028179.png一、Docker 介绍

1. 下载 Dcoker 依的赖环境

想安装Docker,需要先将依赖的环境全部下载下来,就像Maven依赖JDK一样
yum -y install yum-utils device-mapper-persistent-data lvm2

2. 指定 Docker 镜像源

默认下载Docker会去国外服务器下载,速度较慢,可以设置为阿里云镜像源,速度更快
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

3. 安装 Docker

yum makecache fast
yum -y install docker-ce

4. 启动 Docker 并测试

安装成功后,需要手动启动,设置为开机启动,并测试一下 Docker
#启动docker服务
systemctl start docker
#设置开机自动启动
systemctl enable docker
#测试
docker run hello-world

二、Docker 的中央仓库

1.Docker官方的中央仓库:这个仓库是镜像最全的,但是下载速度较慢。
https://hub.docker.com/
2.国内的镜像网站:网易蜂巢,daoCloud等,下载速度快,但是镜像相对不全。
https://c.163yun.com/hub#/home 
http://hub.daocloud.io/ (推荐使用)
3.在公司内部会采用私服的方式拉取镜像(添加配置)
#需要创建 /etc/docker/daemon.json,并添加如下内容
{
    "registry-mirrors":\["https://registry.docker-cn.com"\],
    "insecure-registries":\["ip:port"\]
}
#重启两个服务
systemctl daemon-reload
systemctl restart docker

三、镜像的操作

image-20200828222052873.png

底层原理

docker怎么工作的?

Docker是个C-S结构系统,Docker守护进程运行在主机上。通过Socket从客户端访问。

Docker server 接收Docker-Client指令,就会执行命令。

Docker为什么比虚拟机快

  1. Docker有着比虚拟机更少的抽象层。
  2. docker用宿主机的内核,vm需要GUEST OS

image-20200828222052873.png

1. 拉取镜像

从中央仓库拉取镜像到本地
docker pull 镜像名称\[:tag\]
#举个栗子:docker pull daocloud.io/library/tomcat:8.5.15-jre8
# 如果不写tag默认latest
# 分层下载

2. 查看本地全部镜像

查看本地已经安装过的镜像信息,包含标识,名称,版本,更新时间,大小
docker images
#可选项
-a --all # 显示所有镜像
-q --quiet # 只显示镜像id

3. 删除本地镜像

镜像会占用磁盘空间,可以直接手动删除,标识通过查看获取
docker rmi 镜像的标识
docker rmi $(docker image -qa)

4. 镜像的导入导出

如果因为网络原因可以通过硬盘的方式传输镜像,虽然不规范,但是有效,但是这种方式导出的镜像名称和版本都是null,需要手动修改
#将本地的镜像导出
docker save -o 导出的路径 镜像id
#加载本地的镜像文件
docker load -i 镜像文件
#修改镜像文件
docker tag 镜像id 新镜像名称:版本
# 帮助命令
docker version #显示版本信息
docker info # docker 系统信息,包括镜像和容器数量
docker 命令 --help

docker tag : 标记本地镜像,将其归入某一仓库。
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
[root@localhost ~]$ docker tag centos centos:v1
[root@localhost ~]$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              latest              1e1148e4cc2c        2 weeks ago         202MB
centos              v1                  1e1148e4cc2c        2 weeks ago         202MB
# 搜索镜像
docker search 名字
D:\workspace\redis\composetest> docker search python
NAME                             DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
python                           Python is an interpreted, interactive, objec…   5448                [OK]
django                           Django is a free web application framework, …   991                 [OK]
pypy                             PyPy is a fast, compliant alternative implem…   249                 [OK]
#可选项
   -f, --filter filter   Filter output based on conditions provided
      --format string   Pretty-print search using a Go template
      --limit int       Max number of search results (default 25)
      --no-trunc        Don't truncate output
      
D:\workspace\redis\composetest> docker search python --filter=STARS=3000 #star 3000 以上
      

四、容器的操作

1. 运行容器

运行容器需要定制具体镜像,如果镜像不存在,会直接下载
#简单操作
docker run 镜像的标识|镜像的名称\[:tag\]
#常用的参数
docker run -d -p 宿主机端口:容器端口 --name 容器名称 镜像的标识|镜像名称\[:tag\]
#-d:代表后台运行容器
#-p 宿主机端口:容器端口:为了映射当前Linux的端口和容器的端口
#--name 容器名称:指定容器的名称
# -it 交互方式运行
# 显示日志
-tf # 显示日志
--tail number # 要显示日志条数
docker logs -tf --tail 10 容器id
#查看容器内部的进程信息
D:\redis\docker-slave> docker top 728
PID                 USER                TIME                COMMAND
56518               999                 0:00                redis-server *:6379
# 查看容器元数据
docker inspect 容器id
[
    {
        "Id": "7280041d5b930c77b4e9f2280af60b86ade396bed9a34bece6ce61c270aa21fd",
        "Created": "2020-08-29T01:43:12.373345412Z",
        "Path": "docker-entrypoint.sh",
        "Args": [
            "redis-server"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 56518,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-08-29T01:43:13.930533126Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:7eed8df88d3b3574ed937381f06e715d1b73be03ffed6acca58a6fa9f6ff3d64",
        "ResolvConfPath": "/var/lib/docker/containers/7280041d5b930c77b4e9f2280af60b86ade396bed9a34bece6ce61c270aa21fd/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/7280041d5b930c77b4e9f2280af60b86ade396bed9a34bece6ce61c270aa21fd/hostname",
        "HostsPath": "/var/lib/docker/containers/7280041d5b930c77b4e9f2280af60b86ade396bed9a34bece6ce61c270aa21fd/hosts",
        "LogPath": "/var/lib/docker/containers/7280041d5b930c77b4e9f2280af60b86ade396bed9a34bece6ce61c270aa21fd/7280041d5b930c77b4e9f2280af60b86ade396bed9a34bece6ce61c270aa21fd-json.log",
        "Name": "/nifty_curran",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Capabilities": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "ConsoleSize": [
                50,
                164
            ],
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "KernelMemory": 0,
            "KernelMemoryTCP": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/5055750f20f49cd3f5684a5b7388ed2ecff79b3c641de99017c6e4665cfa9d0c-init/diff:/var/lib/docker/overlay2/13911871e4b70ed520838d895cfafc2175ea94db980ed05d498da9396bef0cde/diff:/var/lib/docker/overlay2/f1b8cff2012374f1cfeb461acd64c07a5d7b1e2174a0afe90c60b92fac22d06e/diff:/var/lib/docker/overlay2/1a17bb8a0244a0fde7e4cd7d37f906b46672d701a70660f9cdf46df740c4a18a/diff:/var/lib/docker/overlay2/dae503da0441e4788b1e8347e1508bffcf8baefb12aede97fd290f007c45503a/diff:/var/lib/docker/overlay2/f6a29e2348b308c119e123d842b35f0c6b76004d2290097fde3bd54196bfc9d3/diff:/var/lib/docker/overlay2/80e99d6b63b85ad48523ae8625e5ce027b81a2da790683185649081ada1a85f3/diff",
                "MergedDir": "/var/lib/docker/overlay2/5055750f20f49cd3f5684a5b7388ed2ecff79b3c641de99017c6e4665cfa9d0c/merged",
                "UpperDir": "/var/lib/docker/overlay2/5055750f20f49cd3f5684a5b7388ed2ecff79b3c641de99017c6e4665cfa9d0c/diff",
                "WorkDir": "/var/lib/docker/overlay2/5055750f20f49cd3f5684a5b7388ed2ecff79b3c641de99017c6e4665cfa9d0c/work"
            },
            "Name": "overlay2"
        },
        "SizeRw": 0,
        "SizeRootFs": 98205103,
        "Mounts": [
            {
                "Type": "volume",
                "Name": "1a6c8df98c1ecc6ed763c633f6ebac8e4115271e58f8923344f8a47aa925ff35",
                "Source": "/var/lib/docker/volumes/1a6c8df98c1ecc6ed763c633f6ebac8e4115271e58f8923344f8a47aa925ff35/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
            "Hostname": "7280041d5b93",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "ExposedPorts": {
                "6379/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOSU_VERSION=1.11",
                "REDIS_VERSION=5.0.7",
                "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-5.0.7.tar.gz",
                "REDIS_DOWNLOAD_SHA=61db74eabf6801f057fd24b590232f2f337d422280fd19486eca03be87d3a82b"
            ],
            "Cmd": [
                "redis-server"
            ],
            "Image": "7ee",
            "Volumes": {
                "/data": {}
            },
            "WorkingDir": "/data",
            "Entrypoint": [
                "docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "74e1dff4096ff21f20db24123f48110791308905ea8395538bc7db826ffc86d0",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "6379/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/74e1dff4096f",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "2de94cf420fb02075021db2727e23f7beb813f202b468336cdba7ca00c62ea2d",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "5e4593468809d742a56eaeb8b9459a62f8c065e61496a6b4a2548edb314dbba0",
                    "EndpointID": "2de94cf420fb02075021db2727e23f7beb813f202b468336cdba7ca00c62ea2d",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]

2. 查看正在运行的容器

查看全部正在运行的容器信息
docker ps \[-qa\]
#-a 查看全部的容器,包括没有运行
#-q 只查看容器的标识
#-n=? 显示最近的容器

3. 查看容器日志

查看容器日志,以查看容器运行的信息
docker logs -f 容器id
#-f:可以滚动查看日志的最后几行

4. 进入容器的内部

通常容器都是后台方式运行,需要进入容器修改配置

方式一命令
docker exec -it 容器id bash
进入容器后开启新的终端,可以在里面操作

方式二
docker attach 容器 id
进入容器正在执行的终端,不会启动新的进程

5. 复制内容到容器

将宿主机的文件复制到容器内部的指定目录
docker cp 文件名称 容器id:容器内部路径

将容器内的文件copy出
docker cp 容器id:容器内部路径  文件路径

6. 重启 & 启动 & 停止 & 删除容器

退出容器 exit
容器不停止退出容器 ctrl+P+Q

容器的启动,停止,删除等操作,后续会经常使用到
#重新启动容器
docker restart 容器id
#启动停止运行的容器
docker start 容器id
 
#停止指定的容器(删除容器前,需要先停止容器)
docker stop 容器id
#强制停止当前容器
docker kill 容器id
#停止全部容器
docker stop $(docker ps -qa)
#删除指定容器
docker rm 容器id
#删除全部容器
docker rm $(docker ps -qa)
docker ps -a -q | xargs docker rm

image-20200828211718052.png
image-20200829101258541.png
image-20200829101330576.png

五、Docker 应用

nginx

# nginx
1. 搜索镜像 docker search 镜像那么
2. 获取镜像 docker pull 镜像
3. 运行参数:docker run -d --name nginx1 -p 3366:80 nginx
4. 测试:
        linux:curl localhost:3366
        windows: $R = Invoke-WebRequest -URI http://localhost:3366
   进入容器:
D:\redis\docker-slave> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
a160b0ef6749        nginx               "/docker-entrypoint.…"   18 minutes ago      Up 18 minutes       0.0.0.0:6666->80/tcp   nginx1
PS D:\redis\docker-slave> docker exec -it a16 bash
root@a160b0ef6749:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@a160b0ef6749:/# cd /etc/nginx
root@a160b0ef6749:/etc/nginx# ls
conf.d  fastcgi_params  koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params  uwsgi_params  win-utf

powershell中使用curl

#请求地址
- Uri $uri
#添加header
-Headers @{"content-type"="application/json";"authorization"="bearer token"}
#指定Method
-Method Get
#将获取到的content输出到文件
-OutFile 'c:\Users\rmiao\temp\content.txt'
C:\Users\wweim> get-help invoke-webrequest

名称
    Invoke-WebRequest

语法
    Invoke-WebRequest [-Uri] <uri>  [<CommonParameters>]


别名
    iwr
    wget
    curl


备注
    Get-Help 在此计算机上找不到该 cmdlet 的帮助文件。它仅显示部分帮助。
        -- 若要下载并安装包含此 cmdlet 的模块的帮助文件,请使用 Update-Help。
        -- 若要联机查看此 cmdlet 的帮助主题,请键入: "Get-Help Invoke-WebRequest -Online" 或
           转到 https://go.microsoft.com/fwlink/?LinkID=217035。

C:\Users\wweim> $R = Invoke-WebRequest -URI http://www.bing.com?q=how+many+feet+in+a+mile
C:\Users\wweim> $R
StatusCode        : 200
StatusDescription : OK
Content           : <!DOCTYPE html><html lang="zh" xml:lang="zh" 
RawContent        : HTTP/1.1 200 OK
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 118264
...... # 省略n多字符

tomcat

docker run -it --rm tomcat:9.0
# 用完即删容器,一般用来测试

docker pull tomcat:9.0
docker run -d -p 3355:8080 --name tomcat1 2ae
docker exec -it tomcat1 bash

//webapps 缺少命令
方式一:cp -r  ./webapps.dist/* ./webapps/

es+kibana

# es 暴露端口多,十分耗内存,数据一般放在安全目录挂载
# --net somenetwork 网络配置
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

#es 耗内存,1.xG
# 查看 docker stats

# 通过-e进行配置,限制内存
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64n -Xmx512m" elasticsearch:7.6.2

可视化

portainer docker图形化管理工具

docker run -d -p 9000:9000 --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    --name prtainer-test \
    docker.io/portainer/portainer

image-20200829125729049.png

Rancher(CI/CD)

Docker镜像讲解

镜像是轻量级可独立运行的软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需要的内容,包括代码、运行时的库、环境变量和配置文件

所有的应用直接打包docker镜像,可直接运行

Docker镜像加载原理

UnionFS(联合文件系统)

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

特性:一次加载多个文件系统,但从外面只看到一个文件系统,联合加载会把各层文件系统累加起来,这样最终的文件系统会包含所有底层的文件
image-20200829153910003.png

Docker镜像加载原理

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

  • bootfs(boot file system) 主要包含bootloader和kernel, bpotloader 主要是引导加载kernel,当我们加载镜像的时候,会通过bootloader加载kernal,Docker镜像最底层是bootfs,当boot加载完成后整个kernal内核都在内存中了,bootfs也就可以卸载,值得注意的是,bootfs是被所有镜像共用的,许多镜像images都是在base image(rootfs)基础上叠加的
  • rootfs (root file system),在bootfs之 上.包含的就是典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是 各种不同的操作系统发行版,比如Ubuntu, Centos等等 。

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

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

分层理解

共享资源

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

docker镜像都是只读的

当容器启动时,一个新的可写层被加载到镜像的顶部。

这一层通常被称作“容器层”,“容器层”之下都叫“镜像层

commit镜像

docker commit 提交容器成为一个新副本

# 命令和git原理类似
# 将我们操作过的容器提交为一个镜像
docker commit -m="提交描述信息" -a="作者" 容器id 目标镜像名:[Tag]

#docker commit -a="xian" -m="add webapps app"  eda09906a31c tomcat02:1.0

六、数据卷

docker理念:将应用和环境打包成一个镜像

数据?如果在容器里,容器删除,数据将会丢失 需求:数据持久化

容器持久化和同步操作,容器间也可以共享数据

使用数据卷

方式一:直接使用命令来挂载 -v
docker run -it -v 主机目录:容器内目录 -p 主机端口:容器端口 --name 容器名称 容器id
# windows
docker run -d -v D:\workspace\securityplanform\securityplatform\数据库\redis\pro:/home -p 3355:8080 --name tomcat2 9422

image-20200829163250877.png

为了部署 SSM 的工程,需要使用到 cp 的命令将宿主机内的 ssm.war 文件复制到容器内部。

数据卷:将宿主机的一个目录映射到容器的一个目录中。

可以在宿主机中操作目录中的内容,那么容器内部映射的文件,也会跟着一起改变。

1. 创建数据卷

#创建数据卷后,默认会存放在一个目录下/var/lib/docker/volumes/数据卷名称/\_data
docker volume create 数据卷名称

2. 查看全部数据卷

#查看全部数据卷信息
docker volume ls

3. 查看数据卷详情

#查看数据卷的详细信息,可以查询到存放的路径,创建时间等等
docker volume inspect 数据卷名称

4. 删除数据卷

#删除指定的数据卷
docker volume rm 数据卷名称

5. 容器映射数据卷

#通过数据卷名称映射,如果数据卷不存在。Docker会帮你自动创建,会将容器内部自带的文件,存储在默认的存放路径中。
docker run -d -p 8080:8080 --name tomcat -v 数据卷名称:容器内部的路径 镜像id
 
#通过路径映射数据卷,直接指定一个路径作为数据卷的存放位置。但是这个路径下是空的。
docker run -d -p 8080:8080 --name tomcat -v 路径(/root/自己创建的文件夹):容器内部的路径 镜像id

实战msql


mysql 数据持久化

映射的data目录中不能有文件

docker pull mysql:5.7
docker run -d -p 3310:3306 -v D:\workspace\securityplanform\securityplatform\数据库\redis\pro\mysql\data:/etc/mysql/conf.d -v D:\workspace\securityplanform\securityplatform\数据库\redis\pro\mysql\data:/var/lib/mysql -e MSQL_ROOT_PASSWORD=666 --name mysql1  mysql

具名挂载和匿名挂载

匿名挂载:即在进行数据卷挂载的时候不指定宿主机的数据卷目录
    -v 容器路径
    docker run -d -P --name nginx1 -v /etc/nginx nginx
D:\workspace\securityplanform\securityplatform\数据库\redis\pro> docker volume ls
DRIVER              VOLUME NAME
local               1a6c8df98c1ecc6ed763c633f6ebac8e4115271e58f8923344f8a47aa925ff35
具名挂载:
    docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx 
    docker volumn inspect juming-nginx

所有docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/XXX
docker volumn ls 查看所有的卷都在这个位置/var/lib/docker/volumns

如何确定是匿名挂载还是具名挂载呢?

-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载

拓展
(1)通过 -v 容器内路径:ro rw 改变读写权限

ro readonly #只读
rw readwrite #可读可写

(2)一旦这个设定了容器权限,容器对我们挂载出来的内容就有限定了

docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx

(3)ro

只要看到ro就说明这个路径只能通过宿主机来改变,容器内部是无法操作的

数据卷容器

多个mysql同步数据

docker run -it --name docker01 zs:1.0
docker run -it -d --name docker03 --volumes-from docker01 
docker run -it -d --name docker03 --volumes-from docker02
移除己挂载卷的容器,无论是最初的dbstore容器,还是其后的db1或db2容器,卷都不会被移除。要将卷从硬盘上移除,必须使用docker rm -v命令删除最后一个引用了该卷的容器。

七、Dockerfile 自定义镜像

dockerfile 是用来构建docker镜像文件!命令参数脚本

构建步骤:

1、编写一个dockerfile文件

2、docker build 构建成为一个镜像

3、docker run 运行镜像

4、docker push 发布镜像(Docker hub、阿里云)

FROM scratch
ADD centos-7-x86_64-docker.tar.xz /

LABEL \
    org.label-schema.schema-version="1.0" \
    org.label-schema.name="CentOS Base Image" \
    org.label-schema.vendor="CentOS" \
    org.label-schema.license="GPLv2" \
    org.label-schema.build-date="20200809" \
    org.opencontainers.image.title="CentOS Base Image" \
    org.opencontainers.image.vendor="CentOS" \
    org.opencontainers.image.licenses="GPL-2.0-only" \
    org.opencontainers.image.created="2020-08-09 00:00:00+01:00"

CMD ["/bin/bash"]

dockerfile基础知识:

1、每个保留关键字(指令)都必须是大写字母

2、执行从上到下顺序

3、# 注释

4、每个指令都会提交一个新的镜像层

1.Dockerfile:构建文件

DockerImage:通过Dockerfile构建生成的镜像,最终发布和运行的产品。

DockerContainer:运行起来的镜像,提供服务。

FROM: 基础镜像,
MAINTAINER:  姓名+邮箱,谁写的
RUN:执行的命令,可以编写多个
ADD:类似copy,可自动解压
WORKDIR:声明镜像的默认工作目录
VOLUME:挂载目录
EXPOSE:暴露端口
COPY:将相对路径下的内容复制到自定义镜像中
CMD:指定容器启动要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT:指定容器启动要运行的命令,可以追加命令
ONBUILD:当构建一个被继承Dockerfile,会运行onbuild,触发指令
ENV :构建时设置环境变量
# 创建一个自己的Dockerfile
FROM centos

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "____end____"
CMD /bin/bash

#通过命令自己构建镜像
#docker build -f dockerfile 文件路径 -t镜像名:版本号
 docker build -f Dockerfile -t mycentos:1.0 .
 
#列出镜像变更历史
docker history 

image-20200829213600173.png

CMD 和 ENTRYPOINT

#Dockerfile
FROM centos
CMD ["ls","-a"]

D:\workspace\docker> docker build -f Dockerfile1 -t mycentos:2.0 .

D:\workspace\docker> docker run 8df                                                                                  .
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
PS D:\workspace\docker> docker run 8df -l                                         docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"-l\": executable file not found in $PATH": unknown.

# cmd的清理下,-l替换了cmd命令["ls","-a"],-l不是命令所以报错
# ENTRYPOINT 可以追加命令

FROM centos
ENTRYPOINT ["ls","-a"]

docker run  135 -l                                                                              total 56
drwxr-xr-x   1 root root 4096 Aug 29 14:12 .
drwxr-xr-x   1 root root 4096 Aug 29 14:12 ..
-rwxr-xr-x   1 root root    0 Aug 29 14:12 .dockerenv
lrwxrwxrwx   1 root root    7 May 11  2019 bin -> usr/bin
drwxr-xr-x   5 root root  340 Aug 29 14:12 dev
drwxr-xr-x   1 root root 4096 Aug 29 14:12 etc
drwxr-xr-x   2 root root 4096 May 11  2019 home
lrwxrwxrwx   1 root root    7 May 11  2019 lib -> usr/lib
lrwxrwxrwx   1 root root    9 May 11  2019 lib64 -> usr/lib64
drwx------   2 root root 4096 Aug  9 21:40 lost+found
drwxr-xr-x   2 root root 4096 May 11  2019 media
drwxr-xr-x   2 root root 4096 May 11  2019 mnt
drwxr-xr-x   2 root root 4096 May 11  2019 opt
dr-xr-xr-x 124 root root    0 Aug 29 14:12 proc
dr-xr-x---   2 root root 4096 Aug  9 21:40 root
drwxr-xr-x  11 root root 4096 Aug  9 21:40 run
lrwxrwxrwx   1 root root    8 May 11  2019 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 May 11  2019 srv
dr-xr-xr-x  12 root root    0 Aug 29 14:12 sys
drwxrwxrwt   7 root root 4096 Aug  9 21:40 tmp
drwxr-xr-x  12 root root 4096 Aug  9 21:40 usr
drwxr-xr-x  20 root root 4096 Aug  9 21:40 var

发布镜像

DockerHub
  1. 注册账号
  2. 登录 docker login -u name
  3. docker push

小结

image-20200830152603749.png

Docker网络

理解Docker0

# 查看容器内部网络地址 ip addr,容器启动会得到一个eth0@if583 ip地址,docker分配的
PS D:\workspace\docker> docker exec -it tomacat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd ::
582: eth0@if583: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
# linux能不能ping通(windows 需要设置)
原理

1、每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装docker就会有个网卡docker0桥接模式,使用veth-pair技术。

veth-pair 就是一对的虚拟设备接口,和 tap/tun 设备不同的是,它都是成对出现的。一端连着协议栈,一端彼此相连着

2、容器之间可以ping通

image-20200830131409601.png

结论:tomcat01和tomcat02是公用一个路由器docker0.

所有容器不指定网络的情况下都是通过docker0路由,docker会给容器分配默认可用IP

Docker用的是linux桥接,docker所有的网络接口都是虚拟的,虚拟转发效率高(内部传递文件)

只要容器删除,对应网桥一对就没了
image-20200830145821638.png

--link

如果编写一个微服务,database url=ip;项目不重启,数据库ip换了,可以用名字访问容器吗
PS D:\workspace\docker> docker exec -it tomacat02 ping tomacat01
ping: tomacat01: Name or service not known

#
PS D:\workspace\docker> docker run -d -P --name tomacat03 --link tomacat02 tomcat
1a951a3dd6341bda935f1d1feef6973d50d30126319a67acab6e344bf1de7fb6

# 通过--link
PS D:\workspace\docker> docker exec -it tomacat03 ping tomacat02
PING tomacat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomacat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from tomacat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.042 ms
64 bytes from tomacat02 (172.17.0.3): icmp_seq=3 ttl=64 time=0.042 ms
# 反向ping不行
PS D:\workspace\docker> docker exec -it tomacat02 ping tomacat03
ping: tomacat03: Name or service not known

PS D:\workspace\docker> docker network ls
NETWORK ID          NAME                                     DRIVER              SCOPE
5e4593468809        bridge                                   bridge              local
f68af27aa78c        composetest_default                      bridge              local
387f0fb5be1a        host                                     host                local
51a0d05b7a14        none                                     null                local
2da31029bce4        scms-promotion-plan-management_default   bridge              local
PS D:\workspace\docker> docker inspect network 5e4
[
    {
        "Name": "bridge",
        "Id": "5e4593468809d742a56eaeb8b9459a62f8c065e61496a6b4a2548edb314dbba0",
        "Created": "2020-08-17T10:27:33.045795472Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
         "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "1a951a3dd6341bda935f1d1feef6973d50d30126319a67acab6e344bf1de7fb6": {
                "Name": "tomacat03",
                "EndpointID": "9337b23669e73d74878b86487dc4c79861378f87ad326ec9727a55ee1923a1bb",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            },
            "281ca3daf0e2c87f2dfbe982b62d1a258d3842e28fe1b6baedc2c0abc108088c": {
                "Name": "tomacat01",
                "EndpointID": "c2d72c0712778ad2f6f7ac2177f00d987281ce0481827b30039bf87618eba1ec",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "9646a8851e1df53c7e4716c1a6a5c7178e7bcfe0a7ced226735191fc57888fb4": {
                "Name": "tomacat02",
                "EndpointID": "b391a9d421b4006c9bf76041cea1cfcd026bd5be5d49af8e0bd4d19006456905",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
# 查看host配置
PS D:\workspace\docker> docker exec -it tomacat03 cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3      tomacat02 9646a8851e1d
172.17.0.4      1a951a3dd634
本质探究: --link就是在hosts中加了一个映射
自定义网络不适用docker0
docker0问题:不支持容器名连接访问

自定义网络

image-20200830154854649.png

查看所有docker网络

网络模式

bridge: 桥接docker(默认)

none: 不配置网络

host: 和宿主机共享网络

container:容器内网络联通(用的少,局限很大)

测试

# 我们直接启动的命令 --net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 --net bridge tomcat

#docker0 默认,域名不能访问 --link可以连接

#可自定义网络
D:\workspace\docker> docker network create --help

Usage:  docker network create [OPTIONS] NETWORK

Create a network

Options:
      --attachable           Enable manual container attachment
      --aux-address map      Auxiliary IPv4 or IPv6 addresses used by
                             Network driver (default map[])
      --config-from string   The network from which copying the configuration
      --config-only          Create a configuration only network
  -d, --driver string        Driver to manage the Network (default "bridge")
      --gateway strings      IPv4 or IPv6 Gateway for the master subnet
      --ingress              Create swarm routing-mesh network
      --internal             Restrict external access to the network
      --ip-range strings     Allocate container ip from a sub-range
      --ipam-driver string   IP Address Management Driver (default "default")
      --ipam-opt map         Set IPAM driver specific options (default map[])
      --ipv6                 Enable IPv6 networking
      --label list           Set metadata on a network
  -o, --opt map              Set driver specific options (default map[])
      --scope string         Control the network's scope
      --subnet strings       Subnet in CIDR format that represents a
                             network segment
 
# 创建自定义为网络
# --driver bridge
# --subnet 192.168.0.0/16
# --gateway 192.168.0.1
D:\workspace\docker> docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
63e20b3b606c0cb98d8904f68c9a066664ccc1f8b979051cdb0a95c5dc6ccb8a
PS D:\workspace\docker> docker network ls
NETWORK ID          NAME                                     DRIVER              SCOPE
5e4593468809        bridge                                   bridge              local
f68af27aa78c        composetest_default                      bridge              local
387f0fb5be1a        host                                     host                local
63e20b3b606c        mynet                                    bridge              local
# 查看自己创建的网络
PS D:\workspace\docker> docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "63e20b3b606c0cb98d8904f68c9a066664ccc1f8b979051cdb0a95c5dc6ccb8a",
        "Created": "2020-08-30T08:03:45.734311737Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

PS D:\workspace\docker> docker run -d -P --name tomcat-net-01 --net mynet tomcat
bd409a23f48669cff91f3b7f37b75820bd7a294f134ad130b23b5cc6e0694c23
PS D:\workspace\docker> docker run -d -P --name tomcat-net-02 --net mynet tomcat
638347bc00a706b39a381514da67f9fcdb253ae8bf69c38ca7961fb658533a46
PS D:\workspace\docker> docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "63e20b3b606c0cb98d8904f68c9a066664ccc1f8b979051cdb0a95c5dc6ccb8a",
        "Created": "2020-08-30T08:03:45.734311737Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "192.168.0.0/16",
                    "Gateway": "192.168.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        # 自己的网络多了几个容器
        "Containers": {
            "638347bc00a706b39a381514da67f9fcdb253ae8bf69c38ca7961fb658533a46": {
                "Name": "tomcat-net-02",
                "EndpointID": "69d1c5df2cd71bbbb80bf234be69ca11b58db5753df22df6cee75c1f0168b8e5",
                "MacAddress": "02:42:c0:a8:00:03",
                "IPv4Address": "192.168.0.3/16",
                "IPv6Address": ""
            },
            "bd409a23f48669cff91f3b7f37b75820bd7a294f134ad130b23b5cc6e0694c23": {
                "Name": "tomcat-net-01",
                "EndpointID": "de361dfba548fbf32d08701c458b278a36c150825ea304532afc08f999e1a6e8",
                "MacAddress": "02:42:c0:a8:00:02",
                "IPv4Address": "192.168.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
# 再次测试,不使用--link也可以连接
PS D:\workspace\docker> docker exec -it tomcat-net-01 ping tomcat-net-02
PING tomcat-net-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.151 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=2 ttl=64 time=0.072 ms
64 bytes from tomcat-net-02.mynet (192.168.0.3): icmp_seq=3 ttl=64 time=0.101 ms

自定义网络docker已经维护了对应关系,推荐!

好处:不同集群使用不同网络,保证集群的安全和健康

网络联通

image-20200830161857154.png

image-20200830162245626.png

PS D:\workspace\docker> docker run -d -P --name tomcat01  tomcat
29a3dfc4017d32a9549d1702db543ca9438a79ce9014f650e2a0d0007722f6fd
PS D:\workspace\docker> docker run -d -P --name tomcat02  tomcat
7bb3e11e1360fc26d582072c403a123dcc38eaa07f0e942163bcfc8db55371c5
# 测试打通 tomcat01 到 mynet
PS D:\workspace\docker> docker network connect mynet tomcat01
# 一个容器两个ip地址

image-20200830162605758.png

部署redis集群

shell 脚本

# 创建脚本
docker network create redis --subnet 172.38.0.0/16

#通过脚本创建6个redis配置
for port in $(seq 1 6):
do \
mkdir -p ./redis/node${port}/conf
touch ./redis/node${port}/conf/redis.conf
cat << EOF >./redis/node${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

#启动集群
docker run -p 6371:6379 -p 16371:16379 --name redis-1 -v D:\workspace\docker\redis/node1/data:/data -v D:\workspace\docker\redis/node1/conf/redis.conf:/etc/redis/redis.conf 
-d --net redis --ip 172.38.0.11 redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf

#redis 集群使用sh进入
PS D:\workspace\docker> docker exec -it redis-1 sh

# 创建集群配置
/data # redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...

# -c 是进入集群
/data # redis-cli -c
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:136
cluster_stats_messages_pong_sent:139
cluster_stats_messages_sent:275
cluster_stats_messages_ping_received:134
cluster_stats_messages_pong_received:136
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:275
127.0.0.1:6379> cluster nodes
ec65883b496e004ecde689d8ea61c6e4c148f753 172.38.0.14:6379@16379 slave c220031b9b01129114530f5587f7b9a11f4c70a4 0 1598779805000 4 connected
b443c1c7a7a9461022036df358127a4daee553c1 172.38.0.16:6379@16379 slave 00845f2012af8c700ae6f4314391f0cf0b14b34a 0 1598779805598 6 connected
dbbb01b6c43cc1b2ddbb9729757ea8e9221259c9 172.38.0.15:6379@16379 slave 023b067527c89690e947d6ea6b1f3f8dddc377c8 0 1598779805598 5 connected
00845f2012af8c700ae6f4314391f0cf0b14b34a 172.38.0.12:6379@16379 master - 0 1598779805096 2 connected 5461-10922
c220031b9b01129114530f5587f7b9a11f4c70a4 172.38.0.13:6379@16379 master - 0 1598779805598 3 connected 10923-16383
023b067527c89690e947d6ea6b1f3f8dddc377c8 172.38.0.11:6379@16379 myself,master - 0 1598779804000 1 connected 0-5460
127.0.0.1:6379>

八、Docker-Compose

1. 下载并安装 Docker-Compose

定义、运行多个容器

YAML file 配置文件

命令

三步骤:

  1. Dockerfile保证我们的项目在任何地方可以运行
  2. docker-compose.yml services
  3. 启动项目 docker-compose up

作用:批量容器编排

compose是官方开源项目,需要自己安装

Compose:重要概念。

  • 服务services,容器、应用。(web、redis、mysql)
  • 项目project。一组关联的容器

官方案列

[https://docs.docker.com/compose/gettingstarted/]:

Docker-compose
4 评论
    gdzuiguszeSogo BrowserWindows 10
    10月5日回复

    新盘 上车集合 留下 我要发发 立马进裙

    hoybxfwlggSogo BrowserWindows 10
    10月7日回复

    2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
    新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
    新车首发,新的一年,只带想赚米的人coinsrore.com
    新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
    做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
    新车上路,只带前10个人coinsrore.com
    新盘首开 新盘首开 征召客户!!!coinsrore.com
    新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
    新车即将上线 真正的项目,期待你的参与coinsrore.com
    新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
    新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com

    11月10日回复

    东方明珠客服开户联系方式【182-8836-2750—】?μ- cxs20250806
    东方明珠客服电话联系方式【182-8836-2750—】?- cxs20250806】
    东方明珠开户流程【182-8836-2750—】?薇- cxs20250806】
    东方明珠客服怎么联系【182-8836-2750—】?薇- cxs20250806】

    11月21日回复

    华纳圣淘沙公司开户新手教程

    零基础学会(183-8890-9465薇-STS5099)
    华纳圣淘沙公司开户

    华纳圣淘沙公司开户保姆级教程(183-8890-9465薇-STS5099)

    一步步教你开通华纳圣淘沙公司账户(183-8890-9465薇-STS5099)

    华纳圣淘沙公司开户分步图解

    首次开户必看:(183-8890-9465薇-STS5099)
    华纳圣淘沙全攻略

    华纳圣淘沙公司开户实操手册(183-8890-9465薇-STS5099)
    华纳圣淘沙开户流程视频教程

    手把手教学:(183-8890-9465薇-STS5099)
    华纳圣淘沙公司开户

    华纳圣淘沙公司开户完全指南(183-8890-9465薇-STS5099)