热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

经验拾忆(纯手工)=>Docker语法全面回忆

HelloDocker官方安装教程:https:docs.docker.cominstalllinuxdocker-ceubuntu进去选好对应系统发行版,照着命令复制-粘贴-运行
Hello Docker

官方安装教程:https://docs.docker.com/install/linux/docker-ce/ubuntu/
进去选好对应系统/发行版, 照着命令复制-粘贴-运行。 就可以安装成功(根本不需要多余操作)
Image(镜像)

  • docker search

    docker search python # 列出dockerhub 提供的 image

  • docker pull(下载)

    docker pull python:3.7 # 从 dockerhub下载 image 冒号:数字 用来指定版本(不指定就是最新版本)

  • docker images(列出)

    docker images # 列出本地镜像 (或 docker image ls)
    docker images py* # 也可以通过名称来筛选查看 image, 也可使用通配符

  • docker rmi(删除)

    docker rmi "image名" 或 "imageID" # 删除 image
    docker rmi python -f # 强制删除(当image内有容器运行无法删除时,可通过-f强制删除)
    如果两个image有相同 "imageID",会删除失败, 这时可以考虑用 "image名" 来删除
    如果两个image有相同的 "image名", 那么可以考虑用 "image名:Tag" 来删除

  • docker save(保存备份)

    方式1:docker save python > python.tar # 可追加多个image来 把多个image打包保存
    方式2: docker save python -o python.tar
    python.tar文件 可分享传输,给别人还原加载使用
    注: 上令为例,如果有多个python版本, 那么会将所有python images 都会打包在一起保存
    如果你有多个镜像, 为了避免混淆,一定要指定一下版本号 docker save python:latest

  • docker load(还原)

    方式1: docker load -i python.tar
    方式2: docker load

  • docker tag(改名,改版本号)

    docker tag python:latest py:3.7 # 把 "python:latest" 改为 "py:3.7 "
    注1: 若image名不为, 那么首先会将 image 复制创建一份,然后改名
    注2: 若原image名为 ,那么 改名后,会直接在原有image上直接改名

  • docker inspect(查看详细信息)

    docker inspect python

  • docker history(查看分层历史信息)

    docker history mypython:3.7

Container(容器)
  • docker create(创建)

    docker create --name py-con python:latest # --name后自定义名字, 最后指定哪一个镜像
    docker create -it python:latest python # 创建带有标准输入环境的容器,并执行python命令
    -t 为了给容器创建一个 terminal
    -i 为了给容器提供一个 标准输入流 (否则,容器终端里无法输入)
    注:创建默认是 created状态, 需要下面 docker start 命令来启动

  • docker start(开启)

    docker start -ai 容器ID # 以标标准环境开启容器
    -a 代表提供标准输出
    -i 同create -i ,提供标准输入

  • docker run(创建+启动, 推荐)

    docker run -it python:latest python # 一套搞定 create+start 的繁杂过程, -it同上不解释
    # 命令防混淆解释: 根据python:latest镜像 ,创建并执行容器,同时执行 python命令
    docker run -d -it python:latest python
    # 其他不变,多加一个 -d, 可以创建并放入 "后台" 执行 (不加-d , 默认"前台")
    docker run -dit --rm python:latest python
    # --rm 参数代表 容器停止,即(exited状态), 就会自动删除。
    docker run --network bridge -itd mypython:latest python
    # --network 代表指定网络(若不指定,默认也是bridge,见下面 网络章节)
    docker run -dit -p 6006:6379 redis
    # 端口映射, 宿主机(6006):容器(6379) (-P代表容器内部所有端口 与宿主机随即映射)
    docker run --restart always
    # --restart always 代表 docker服务重启时, 里面的容器也会跟着重启

  • docker stop(终止,结束)

    docker ps # 查看一下 "运行中容器ID"
    docker stop 容器ID # 停止 "运行中" 的容器 ( 默认 10秒钟后 才停止)
    docker stop -t 0 374 # -t指定时间 0秒后, 即瞬间就可以停止
    扩展(停止所有正在运行的容器):
    docker stop $(docker ps -q) # -q参数代表只显示容器ID

  • docker restart(重启)

    docker restart -t 0 281 # 0秒重启

  • docker pause(暂停)

    docker pause 281 # 暂停容器内的所有进程, 注意是暂停, 不是终止

  • docker unpause(继续)

    docker unpause 281 # 把暂停的容器,继续开启

  • docker ps(查看)

    docker ps # 列出所有 "运行中" 的容器
    docker ps -a # 列出所有 容器

  • docker logs(查看输出日志)

    docker logs 281 # 查看容器内部输出日志
    docker logs -f 281 # -f 代表阻塞监控, (和 tail -f 一个道理)

  • docker rename(重命名)

    docker rename 281 python # 把 281的容器 改名为 python

  • docker inspect(查看容器详细信息)

    docker inspect 374 # 查看容器所有信息

  • docker rm(删除)

    docker rm 容器ID # 删除已停止的容器
    docker rm 容器ID -f # 强制删除(运行中)等特殊情况的容器

  • docker attach(进入到容器命令执行处)

    docker run -itd python:latest python # 新创建容器,名执行 python命令
    docker attach 281 # 直接进入281这个容器,并直接跳到 python控制台内部
    "注: 进入python控制台后,再退出去,就意味着, 容器的退出。"

  • docker exec(执行命令)

    docker exec -it 281 python # 在"容器外部", 执行"内部容器"的 python命令
    "注: 与上一条attach不同的是,退出python控制台后,容器依旧运行!(因为是在容器外面执行的python命令)"

Container and Images(容器与镜像关联)
  • docker commit (把容器”封装”成一个新镜像)

    docker commit 4d mypython:3.7 # 把4d这个容器所有内容,封装为一个"名字:版本"叫"mypython:3.7"的镜像

  • docker export (容器导出为一个文件)

    docker export fc8 -o mypython.tar # 把此容器导出为一个.tar文件 ,和前面说过的 image的 save类似

  • docker import (把export导出的文件导出,并”生成”一个镜像)

    docker import mypython.tar mypython:latest
    注: 把export导出的 mypython.tar文件导入 并 直接创建一个 mypython:latest 的 镜像

  • docker commit & docker import区别

    前面说过:
    docker commit 是 直接把一个container 封装为一个image
    docker import 是 把export导出的container.tar文件 再 导入进来,并重新生成一个 新 image
    docker commit 是继承封装的,并创建具有分层历史记录 (docker history imageID 即可查看)
    docker import 是直接生成的,不具有分层记录 (docker history imageID 即可查看)

网络
  • docker network ls (查看)

    docker network ls
    bridge(网桥):容器默认网络模式
    容器-容器网络连接:
    container1(etho0)--veth1--Docker(bridge)--veth2--container2(etho0)
    容器-宿主机网络连接:
    container1(etho0)--veth1--Docker(bridge)--宿主机(etho0)
    注: veth是创建网络时,自动创建的,不需要手动管理

    host(主机): 容器网络和主机使用同一个网络
    容器-容器网络连接:
    container1(etho0)--宿主机--container2(etho0)
    容器-宿主机网络连接:
    container1(etho0)--宿主机
    容器网络(特殊host):
    container1--container2 # 就是 ‘每个容器互相把对方认作为 宿主机’ 这个意思
    使用方法:
    docker run -it --network container:24f1 mypython:latest ls
    # container:24f1 的container是语法关键词 24f1是连接的对方容器()

    null(无网络):所有容器无网络

  • docker network create (创建)

    docker network create -d bridge mybridge # 可创建多个bridge
    docker network create -d host myhost # 只可创建一个host(默认就有一个,故无法创建)
    docker network create -d null mynull # 只可创建一个null(默认就有一个,故无法创建)

  • docker network rm (删除)

    docker network rm ab5
    注:默认自带的网络不可以删除(null host 和 自带的一个 bridge)

  • docker network connect (给容器绑定网络)

    docker network connect mybridge 4c4 # 给4c4这个容器绑定一个 mybridge网络(自定义的bridge)
    docker inspect 4c4 # 查看一下容器信息,最下面就是网络
    注:一个container 可以绑定 多个bridge 网络,

  • docker network disconnect (给容器 解除绑定的网络)

    docker network disconnect mybridge 4c4 # 给容器解除绑定网络mybridge
    注: 一个container 中 bridge 和 none 网络不可以共存, (若冲突,则先disconnect再connect)
    注2:host 网络不能 connect 和 disconnect

数据卷 (volume)
  • docker volume create(创建数据卷)

    docker volume create myvolume
    注: myvolume为数据卷名

  • docker volume ls(列出数据卷)

    docker volume ls
    注: 若数据卷未指定名字,当 使用docker run -v 方式时,则会新建数据卷ID,并以此ID命名。

  • docker volume prune(删除未被容器使用的 所有 数据卷)

    docker volume prune
    注:容器占用的数据卷,删不了

  • docker volume rm (删除 一个 或 多个 指定数据卷)

    docker volume rm myvolume
    注: 删除 myvolume这个数据卷,当然也可以连续参数,追加删除多个数据卷

  • 挂载数据卷

    """意义: 可以让 宿主机 与 容器 数据联通共享"""
    方式1 (-v参数)
    -v使用方式1:(指定路径映射挂载)
    docker run -itd -v /root:/root mypython:latest python # -v 宿主机路径:容器路径
    测试:
    cd /root
    touch #.txt # 宿主机创建文件 #.txt
    docker exec -it cfb ls /root # 结果可看见容器里面也有 #.txt 文件

    -v使用方式2:(指定数据卷对象 映射挂载)
    docker run -itd -v myvolume:/root mypython:latest python # 冒号前面 变成了myvolume
    注1: 这个myvolume就是一个数据卷对象, 执行上面这条命令,就会为我们自动创建这个数据卷对象
    注2: 由于没有宿主映射路径,那么映射的宿主路径 是什么呢??
    docker volume inspect myvolume # 结果Mountpoint后面的就是,宿主机映射的 默认钩子路径
    cd /var/lib/docker/volumes/myvolume11/_data # 此路径和volume名有关
    touch bbb.txt # 宿主机创建文件 bbb.txt
    docker exec -it 916 ls /root # 打印结果可见,容器内部也有bbb.txt,说明成功共享。

    方式2:(--mount参数,同样包括 -v的两种使用方式, 另外还新增另一种 文件"缓存"挂载方式)
    docker run -itd --mount type=volume,src=myvolume11,dst=/root mypython:latest python
    注:
    type: 指定类型(路径映射: bind)或 (数据卷对象映射: volume) 或(内存映射:tmpfs)
    src: 对应上面方式1(宿主机路径) 或 对应上面方式2(数据卷名) 或 省略此项(对应新增)
    dst: 容器路径
    逗号分隔,其他没变
    docker run -itd --mount type=tmpfs,dst=/root mypython:latest python (tmpfs"缓存"挂载)

    "综上,可总结为3种挂载选择用途":
    一. "宿主路径 与 容器路径" 映射挂载
    二. "数据卷 与 容器路径" 映射挂载
    三. "宿主内存 与 容器路径" 映射挂载

    "综上,可总结为2种挂载参数使用":
    一、 "-v 参数" 2种用途 (路径映射 和 数据卷对象映射)
    二、 "--mount 参数" 3种用途 (路径映射 和 数据卷对象映射 和 内存映射)

  • 容器之间共享数据

    """借助已经拥有数据卷的容器 来 创建一个新容器"""
    docker run -itd --volumes-from 6252 python:latest # 借助6252容器创建新容器,来共享数据卷
    验证:
    docker exec -it 97db touch /root/abc # 新容器 创建一个文件abc
    docker exec -it 6252 ls /root # 旧容器查看 ,也有新文件abc,共享成功

  • 细节注意事项

    一、若将 "空数据卷" 挂载到 容器非空目录中,则"此容器目录下的内容 会copy一份到 数据卷中"
    二、若将 "非空数据卷" 挂载到 容器任意目录中,则"数据卷的数据 会copy到这个目录中,并将此目录原数据隐藏"
    更通俗一点理解就是:
    数据卷大哥说:"如果我这里有数据, 你的容器来挂载,你的数据就会被我这里面的数据覆盖。。"
    数据卷大哥又说:"如果我这里是空的(没有数据),那么 你的容器来挂载, 你的数据就要提供一份给我"

DockerHub(仓库)
  • 无认证 私有仓库

  • 搭建仓库

    docker pull registry # 拉取 registry镜像
    docker run -itd \
    --restart always \ # docker重启时,此容器也跟着重启
    --name myregistry \ # 指定容器名
    -p 6006:5000 \ # 端口映射 (registry服务默认为5000端口,映射为6006)
    -v /root:/var/lib/registry \ # 绑定数据卷 (持久化存储), 冒号后面的容器路径时默认的
    registry # 拉取的 registry镜像
    验证:(一种web服务,所以通过固定Url访问即可)
    外部浏览器验证: 浏览器输入 服务器外网IP:6006/v2/_catalog 即可
    服务器内部验证: curl 127.0.0.1:6006/v2/_catalog

  • 上传镜像

    一、先把要上传的镜像改名
    docker tag mypython:latest 127.0.0.1:6006/mython_hub
    注: 目标名固定格式(需注意,必须此格式): IP:Port/新镜像名
    二、开始上传
    docker push 127.0.0.1:6006/mython_hub # docker push 镜像名,注意这里用ID不好使,必须用这名
    三、验证
    同上面搭建仓库时的验证方法, 可看见结果 repositories列表中多了一个 刚刚上传的镜像
    curl 127.0.0.1:6006/v2/_catalog

  • 下载镜像

    docker pull 127.0.0.1:6006/mython_hub
    注: 这个名就是上传时候的 那个名, 一样的

Dockerfile(配置文件式)
  • Dockerfile认知

    Docker 与 docker命令的关系就相当于 shell编程 与 单条命令
    主要就是把上面讲的所有命令连起来,脚本式执行, 当然dockerfile也有自己的语法关键词。
    Dockerfile是基于缓存,所以里面的文件内容(某条命令) "如果未发生改变,则不会重新执行(用的是缓存)"
    Dockerfile机制:
    一、若在结尾每"追加"一条新命令,重新构建Dockerfile时,"只会执行这个新命令,其他旧命令都会使用缓存"
    二、若新命令 是在"中间插入编写的",则此条新命令"之前的命令用缓存", "之后"的命令都会重新执行一遍,
    三、FROM 关键字是 Dockerfile的入口。
    新命令只要不是 写在 "FROM的下一条", 那么所有新命令及其之后的命令都会在 构建Dockerfile时-->
    触发"层层封装"机制 ,即每条"非缓存命令"运行一遍,都会commit封装一层镜像

  • Dockerfile构建

    docker build /Dockerfile所在路径 -t mypython:v2
    注1: 指定Dockerfile所在路径即可,build会自动帮我们找到dockerfile文件
    注2: 如果Dockerfile就在当前路径下,那么可以用 . 来替代绝对路径
    注3: -t 给镜像指定名字

  • Dockerfile语法

  • FROM

    "下载镜像,类似 docker pull"
    FROM python:latest # 同样可以指定版本号

  • RUN | CMD | ENTRYPOINT

    这三个 命令 都有共同的 2种书写方式:
    一、(exec)格式--当前进程执行
    eg: python -V # 就是玩linux的命令正常写
    二、(shell) 格式--子进程执行
    eg: ["python", "-V"] # 命令与作为字符串列表来书写, 和py的scrapy的shell类似

    RUN:
    "构建镜像过程中"执行的命令, 比如安装东西之类的。。(可写多个)
    CMD:
    启动容器时 执行的命令, 就和 之前说过的 docker run 跟的命令是一样的
    "但是 docker run 要是指定了一个命令,那么 这个CMD配置就会失效"
    ENRTYPOINT:
    和CMD类似, 不过 在docker run 指定新命令是, ENTRYPOINT的命令是不会被覆盖的。都会执行

  • ADD | COPY

    """将宿主机文件 拷贝 到镜像的某个目录中"""
    COPY #.txt /root # 将#.txt 拷贝到 镜像的/root目录中
    ADD #.txt /root # 和COPY一样,不过 ADD可以将压缩文件拷贝进去后,"自动解压"

  • ENV

    """就相当于编程语言的 变量赋值"""
    ENV name=python
    ENV nickname=$name # $name 意为取出 name变量的值

  • WORKDIR

    """切换目录 类似cd命令"""
    WORKDIR /root

  • VOLUME

    """添加数据卷"""
    VOLUME /root # 就相当于前面说过的docker run -v /root, 即自动创建一个数据卷映射到 容器的/root

  • EXPOSE

    """暴露端口"""
    EXPOSE 6379
    EXPOSE 3306 # 可以用多个 EXPOSE 暴露多个端口
    注1: 暴露端口后,可以通过 前面说的 docker run -P 来做自动端口映射
    注2: 或者不暴露端口,直接使用手动映射-p,都是可以的。

  • 官方模板参考网址

    官方文档:https://docs.docker.com/engine/reference/builder/
    各种开源Dockerfile模板:https://github.com/docker-library/docs/tree/master/

Docker Compose
  • Docker-Compose认知

    一、Dockerfile 可以看作是 Docker命令的组合
    二、Docker-Compose 可以看作是 Dockerfile的组合(也称作 容器编排工具)
    三、Docker-Compose 文件默认名为 docoker-compose.yaml
    四、docoker-compose.yaml 文件指令中间都有空格 eg: version: 3.7(3.7之前是有空格的)
    五、docoker-compose.yaml 采用缩进对格式语法进行区分

  • Docker-Compose安装

    官方安装教程:https://docs.docker.com/compose/install/
    从上往下,命令复制-粘贴-运行。。。Easy略

  • Docker-Compose文件指令

    version: "3.7" # 必有
    # 此版本号与docker版本对应地址: https://docs.docker.com/compose/compose-file/

    services: # services关键字,写上就行, 必有
    mypython: # mypython是我随便起个名
    build: . # Dockerfile的路径位置, build是构建Dockerfile文件的
    ports:
    -"6006:3003" # 注意-后面是有空格的,markdown语法充冲突,我就没写空格
    command: xxxx # 覆盖Dockerfile中的 CMD
    depends_on: # 依赖的服务, (被依赖的先执行,也就是myredis先执行)
    -myredis # -后有空格
    myredis: # 同理 myredis 也是我随便起的名
    image: redis # 指定一个成品镜像 类似DockerfilE的 FROM指令
    container_name: myredis # 指定容器名
    networks: # 使用下面创建的mynet网络
    -mynet # (同-后有空格,避免markdown语法冲突)
    volumes: # 使用下面创建的myvolume数据卷,并映射到容器的/root目录
    -myvolume:/root # -后有空格,(特别注意 :后面不允许有空格)
    hostname: myredis
    # 因为容器创建时IP可能动态改变,指定名称,则可通过名称来代替IP
    # 若不指定 hostname, 则默认为服务名, 即 myredis

    networks: # 创建网络
    mynet: # 给网络起名为 mynet
    driver: "bridge" # 指定为桥接模式
    volumes: # 创建数据卷
    myvolume: # 给数据卷起名为 myvolume
    driver: "local" # 默认就是local,即数据卷存储在宿主机的目录下

  • 预检查docker-compose.yml文件语法格式是否有误

    docker-compose config
    注:需要在 docker-compose.yml 所在目录下执行

  • 启动/停止 docker comopse

    docker-compose up # 前台终端阻塞执行(就是执行之后,你不能在终端输入东西了)
    docker-compose up -d # 后台终端非阻塞执行 (作为服务一样后台执行)
    docker-compose stop # 停止编排(即停止 所有 编排运行的容器)

END
推荐阅读
  • 在 CentOS 7 系统中安装 Scrapy 时遇到了一些挑战。尽管 Scrapy 在 Ubuntu 上安装简便,但在 CentOS 7 上需要额外的配置和步骤。本文总结了常见问题及其解决方案,帮助用户顺利安装并使用 Scrapy 进行网络爬虫开发。 ... [详细]
  • 在本次分享中,我将详细介绍我的网络数据爬取项目,包括使用Scrapy-Redis进行分布式爬取的具体配置和多台机器的协同工作。此外,还将探讨从Scrapy到Scrapy-Redis的迁移过程,以及在实际爬取过程中遇到的各种反爬虫策略及其应对方法。 ... [详细]
  • 利用ZFS和Gluster实现分布式存储系统的高效迁移与应用
    本文探讨了在Ubuntu 18.04系统中利用ZFS和Gluster文件系统实现分布式存储系统的高效迁移与应用。通过详细的技术分析和实践案例,展示了这两种文件系统在数据迁移、高可用性和性能优化方面的优势,为分布式存储系统的部署和管理提供了宝贵的参考。 ... [详细]
  • 本文详细介绍了在 Ubuntu 系统上搭建 Hadoop 集群时遇到的 SSH 密钥认证问题及其解决方案。通过本文,读者可以了解如何在多台虚拟机之间实现无密码 SSH 登录,从而顺利启动 Hadoop 集群。 ... [详细]
  • Python 数据可视化实战指南
    本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
  • 在 Ubuntu 中遇到 Samba 服务器故障时,尝试卸载并重新安装 Samba 发现配置文件未重新生成。本文介绍了解决该问题的方法。 ... [详细]
  • Python 3 Scrapy 框架执行流程详解
    本文详细介绍了如何在 Python 3 环境下安装和使用 Scrapy 框架,包括常用命令和执行流程。Scrapy 是一个强大的 Web 抓取框架,适用于数据挖掘、监控和自动化测试等多种场景。 ... [详细]
  • 本文将详细介绍如何在Mac上安装Jupyter Notebook,并提供一些常见的问题解决方法。通过这些步骤,您将能够顺利地在Mac上运行Jupyter Notebook。 ... [详细]
  • 本文详细介绍了 InfluxDB、collectd 和 Grafana 的安装与配置流程。首先,按照启动顺序依次安装并配置 InfluxDB、collectd 和 Grafana。InfluxDB 作为时序数据库,用于存储时间序列数据;collectd 负责数据的采集与传输;Grafana 则用于数据的可视化展示。文中提供了 collectd 的官方文档链接,便于用户参考和进一步了解其配置选项。通过本指南,读者可以轻松搭建一个高效的数据监控系统。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 在Windows系统中安装TensorFlow GPU版的详细指南与常见问题解决
    在Windows系统中安装TensorFlow GPU版是许多深度学习初学者面临的挑战。本文详细介绍了安装过程中的每一个步骤,并针对常见的问题提供了有效的解决方案。通过本文的指导,读者可以顺利地完成安装并避免常见的陷阱。 ... [详细]
  • 在机器学习领域,深入探讨了概率论与数理统计的基础知识,特别是这些理论在数据挖掘中的应用。文章重点分析了偏差(Bias)与方差(Variance)之间的平衡问题,强调了方差反映了不同训练模型之间的差异,例如在K折交叉验证中,不同模型之间的性能差异显著。此外,还讨论了如何通过优化模型选择和参数调整来有效控制这一平衡,以提高模型的泛化能力。 ... [详细]
  • 帝国CMS中的信息归档功能详解及其重要性
    本文详细解析了帝国CMS中的信息归档功能,并探讨了其在内容管理中的重要性。通过归档功能,用户可以有效地管理和组织大量内容,提高网站的运行效率和用户体验。此外,文章还介绍了如何利用该功能进行数据备份和恢复,确保网站数据的安全性和完整性。 ... [详细]
  • FreeBSD环境下PHP GD库安装问题的详细解决方案
    在 FreeBSD 环境下,安装 PHP GD 库时可能会遇到一些常见的问题。本文详细介绍了从配置到编译的完整步骤,包括解决依赖关系、配置选项以及常见错误的处理方法。通过这些详细的指导,开发者可以顺利地在 FreeBSD 上完成 PHP GD 库的安装,确保其正常运行。此外,本文还提供了一些优化建议,帮助提高安装过程的效率和稳定性。 ... [详细]
  • Swoole加密机制的安全性分析与破解可能性探讨
    本文深入分析了Swoole框架的加密机制,探讨了其在实际应用中的安全性,并评估了潜在的破解可能性。研究结果表明,尽管Swoole的加密算法在大多数情况下能够提供有效的安全保护,但在特定场景下仍存在被攻击的风险。文章还提出了一些改进措施,以增强系统的整体安全性。 ... [详细]
author-avatar
一枝红杏出墙来2001
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有