Dockerfile

1.1 Dockerfile简介

什么是Dockerfile
​ Dockerfile就是制作docker镜像的脚本,将我们在上面学到的docker镜像,使用自动化的方式实现出来。

注意事项:

  • 文件名首字母大写
  • 存储Dockerfile的目录, 尽量是空目录
  • 制作的镜像功能尽量单一
  • 制作步骤要尽可能精简

dockerfile的组成

dockerfile中的注释使用: #

  • 基础镜像信息
    • 要制作的新的镜像, 基于那个镜像来制作的
    • 通过 docker images 查看
  • 维护者信息
    • 这个dockerfile是谁写的
  • 镜像操作指令
    • 基于原始进行进行的操作
  • 容器启动指令
    • 基于第三步得到了新镜像
    • 新的镜像启动之后, 在容器中默认执行的指令

Dockerfile使用命令:

#构建镜像命令格式:
docker build -t [镜像名]:[版本号][Dockerfile所在目录]
#构建样例:
docker build -t nginx:v0.2 /opt/dockerfile/nginx/
#参数详解:
	-t        					指定构建后的镜像信息,
	/opt/dockerfile/nginx/      则代表Dockerfile存放位置,如果是当前目录,则用 .()表示

1.2 Dockerfile快速入门

​ 接下来我们快速的使用Dockerfile来基于ubuntu创建一个定制化的镜像:nginx。

#创建Dockerfile专用目录
:~$ mkdir ./docker/images/nginx -p
:~$ cd docker/images/nginx/
#创建Dockerfile文件
:~/docker/images/nginx$ vim Dockerfile

dockerfile内容

# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu

# 镜像作者
MAINTAINER panda kstwoak47@163.com

# 执行命令
RUN mkdir hello
RUN mkdir world
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update  
RUN apt-get install nginx -y

# 对外端口
EXPOSE 80

进行构建操作

#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.1 .
#查看新生成镜像
:~/docker/images/nginx$ docker images
REPOSITORY    TAG     IMAGE ID      CREATED        SIZE
ubuntu-nginx  v0.1    a853de1b8be4  9 seconds ago  208MB
nginx         latest  e548f1a579cf  6 days ago     109MB
ubuntu        latest  0458a4468cbc  4 weeks ago    112MB
#查看构建历史
:~/docker/images/nginx$ docker history a853de1b8be4
IMAGE         CREATED            CREATED BY                         SIZE   COMMENT
#镜像			创建时间             依赖命令                            大小    评论
a853de1b8be4  41 seconds ago     /bin/sh -c #(nop)  EXPOSE 80                  0B      
925825b680fd  42 seconds ago     /bin/sh -c apt-get install nginx -y          56.5MB  
4c57d6c99603  About a minute ago /bin/sh -c apt-get update                     40MB    
b6d030a0d123  About a minute ago /bin/sh -c sed -i's/security.ubuntu.com/mir… 2.77kB  
3357bf8069ca  About a minute ago /bin/sh -c sed -i's/archive.ubuntu.com/mirr… 2.77kB  
7bfb90c1e20d  About a minute ago /bin/sh -c mkdir world                         0B      
972d6ab76d01  About a minute ago /bin/sh -c mkdir hello                         0B      
a76394bfad01  About a minute ago /bin/sh -c #(nop) MAINTAINER panda kstwoak4…  0B    
#注意:
因为容器没有启动命令,所以肯定访问不了

优化刚刚的Dockerfile文件

# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu

# 镜像作者
MAINTAINER panda kstwoak47@163.com

# 执行命令
RUN mkdir hello && mkdir world
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt-get update && apt-get install nginx -y


# 对外端口
EXPOSE 80

运行修改好的Dockerfile进行构建

:~/docker/images/nginx$ docker build -t  ubuntu-nginx:v0.2 .
:~/docker/images/nginx$ docker history ubuntu-nginx:v0.2
IMAGE         CREATED         CREATED BY                                     SIZE    COMMENT
eaba9bd1c4ac  3 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                   0B      
ed08d6e29eb1  3 minutes ago   /bin/sh -c apt-get update && apt-get install…  96.5MB  
eef6238ec5bd  6 minutes ago   /bin/sh -c sed -i 's/archive.ubuntu.com/mirr…  2.77kB  
58f755a1b29c  6 minutes ago   /bin/sh -c mkdir hello &&  mkdir world         0B      
a76394bfad01  25 minutes ago  /bin/sh -c #(nop)  MAINTAINER panda kstwoak4…  0B    
#对比两个镜像的大小
:~/docker/images/nginx$ docker images 
REPOSITORY    TAG   IMAGE ID      CREATED         SIZE
ubuntu-nginx  v0.2  eaba9bd1c4ac  7 seconds ago   208MB
ubuntu-nginx  v0.1  a853de1b8be4  21 minutes ago  208MB
#深度对比连个镜像的大小
:~/docker/images/nginx$ docker inspect a853de1b8be4
        "Size": 208237435,
        "VirtualSize": 208237435,
:~/docker/images/nginx$ docker inspect eaba9bd1c4ac
        "Size": 208234662,
        "VirtualSize": 208234662,

Dockerfile构建过程:
​ 从基础镜像1运行一个容器A

​ 遇到一条Dockerfile指令,都对容器A做一次修改操作

​ 执行完毕一条命令,提交生成一个新镜像2

​ 再基于新的镜像2运行一个容器B

​ 遇到一条Dockerfile指令,都对容器B做一次修改操作

​ 执行完毕一条命令,提交生成一个新镜像3

​ …

**构建过程镜像介绍

​ 构建过程中,创建了很多镜像,这些中间镜像,我们可以直接使用来启动容器,通过查看容器效果,从侧面能看到我们每次构建的效果。提供了镜像调试的能力

1.3 基础指令详解

FROM
FROM
#格式:
    FROM <image>
    FROM <image>:<tag>
#解释:
    #FROM 是 Dockerfile 里的第一条而且只能是除了首行注释之外的第一条指令
    #可以有多个FROM语句,来创建多个image
    #FROM 后面是有效的镜像名称,如果该镜像没有在你的本地仓库,那么就会从远程仓库Pull取,如果远程也没有,就报错失败
    #下面所有的 系统可执行指令 在 FROM 的镜像中执行。

 
MAINTAINER
MAINTAINER
#格式:
    MAINTAINER <name>
#解释:
    #指定该dockerfile文件的维护者信息。类似我们在docker commit 时候使用-a参数指定的信息
RUN
RUN
#格式:
    RUN <command>                                   (shell模式)
    RUN["executable", "param1", "param2"]            (exec 模式)
#解释:
    #表示当前镜像构建时候运行的命令,如果有确认输入的话,一定要在命令中添加 -y
    #如果命令较长,那么可以在命令结尾使用 \ 来换行
    #生产中,推荐使用上面数组的格式
#注释:
    #shell模式:类似于  /bin/bash -c command
    #举例: RUN echo hello
    #exec模式:类似于 RUN["/bin/bash", "-c", "command"]
    #举例: RUN["echo", "hello"]
EXPOSE
EXPOSE
#格式:
    EXPOSE <port> [<port>...]
#解释:
    设置Docker容器对外暴露的端口号,Docker为了安全,不会自动对外打开端口,如果需要外部提供访问,
    还需要启动容器时增加-p或者-P参数对容器的端口进行分配。
#     docker run -itd -p 8888:80
  EXPOSE 80

1.4 运行时指令详解

CMD
CMD
#格式:
    CMD ["executable","param1","param2"]         (exec 模式)推荐
    CMD command param1 param2                     (shell模式)
    CMD ["param1","param2"]          提供给ENTRYPOINT的默认参数;
#解释: 
    #CMD指定容器启动时默认执行的命令
    #每个Dockerfile只能有一条CMD命令,如果指定了多条,只有最后一条会被执行
    #如果你在启动容器的时候使用docker run 指定的运行命令,那么会覆盖CMD命令。
    #举例: CMD ["/usr/sbin/nginx","-g","daemon off;"]
    "/usr/sbin/nginx"   nginx命令
    "-g"				设置配置文件外的全局指令
    "daemon off;"		后台守护程序开启方式 关闭
#CMD指令实践:
    #修改Dockerfile文件内容:
    #在上一个Dockerfile文件内容基础上,末尾增加下面一句话:
    CMD ["/usr/sbin/nginx","-g","daemon off;"]
    #构建镜像
    :~/docker/images/nginx$ docker build  -t ubuntu-nginx:v0.3  .
    #根据镜像创建容器,创建时候,不添加执行命令
    :~/docker/images/nginx$ docker run --name nginx-1 -itd ubuntu-nginx:v0.3
    #根据镜像创建容器,创建时候,添加执行命令/bin/bash
    :~/docker/images/nginx$ docker run  --name nginx-2 -itd ubuntu-nginx:v0.3 /bin/bash
    docker ps
    
    #发现两个容器的命令行是不一样的
    itcast@itcast-virtual-machine:~/docker/images/nginx$ docker ps -a
    CONTAINER ID  IMAGE             COMMAND                 CREATED           NAMES
    921d00c3689f  ubuntu-nginx:v0.3 "/bin/bash"             5 seconds ago    nginx-2
    e6c39be8e696  ubuntu-nginx:v0.3 "/usr/sbin/nginx -g …"  14 seconds ago   nginx-1
    
ENTRYPOINT
ENTRYPOINT
#格式:
    ENTRYPOINT ["executable", "param1","param2"] (exec 模式)
    ENTRYPOINT command param1 param2 (shell 模式)
#解释:
    #和CMD 类似都是配置容器启动后执行的命令,并且不会被docker run 提供的参数覆盖。
    #每个Dockerfile 中只能有一个ENTRYPOINT,当指定多个时,只有最后一个起效。
    #生产中我们可以同时使用ENTRYPOINT 和CMD,
    #想要在docker run 时被覆盖,可以使用"docker run --entrypoint"
#ENTRYPOINT指令实践:
    #修改Dockerfile文件内容:
    #在上一个Dockerfile 文件内容基础上,修改末尾的CMD 为ENTRYPOINT:
    ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
    
    #构建镜像
    :~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.4 .
    
    #根据镜像创建容器,创建时候,不添加执行命令
    :~/docker/images/nginx$ docker run  --name nginx-3 -itd ubuntu-nginx:v0.4
    
    #根据镜像创建容器,创建时候,添加执行命令/bin/bash
    :~/docker/images/nginx$ docker run  --name nginx-4 -itd ubuntu-nginx:v0.4 /bin/bash
    
    #查看ENTRYPOINT是否被覆盖
    :~/docker/images/nginx$ docker ps -a
    CONTAINER ID  IMAGE               COMMAND                  CREATED              NAMES
    e7a2f0d0924e  ubuntu-nginx:v0.4   "/usr/sbin/nginx -g …"   59 seconds ago       nginx-4
    c92b2505e28e  ubuntu-nginx:v0.4   "/usr/sbin/nginx -g …"   About a minute ago   nginx-3
    
    #根据镜像创建容器,创建时候,使用--entrypoint参数,添加执行命令/bin/bash
    docker run  --entrypoint "/bin/bash" --name nginx-5 -itd ubuntu-nginx:v0.4
    
    #查看ENTRYPOINT是否被覆盖
    :~/docker/images/nginx$ docker ps 
    CONTAINER ID  IMAGE               COMMAND                  CREATED              NAMES
    6c54726b2d96  ubuntu-nginx:v0.4   "/bin/bash"              3 seconds ago        nginx-5

CMD ENTRYPOINT 综合使用实践
#修改Dockerfile文件内容:

# 在上一个Dockerfile文件内容基础上,修改末尾的ENTRYPOINT

    :~/docker/images/nginx$ vim Dockerfile
    ENTRYPOINT ["/usr/sbin/nginx"]
    CMD ["-g"]
    #构建镜像
    :~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.5 .
    #根据镜像创建容器,创建时候,不添加执行命令
    :~/docker/images/nginx$ docker run --name nginx-6 -d ubuntu-nginx:v0.5
    
    #查看效果
   :~/docker/images/nginx$ docker ps -a 
    CONTAINER ID   IMAGE               COMMAND                  CREATED         NAMES
    e28875d281eb   ubuntu-nginx:v0.5   "/usr/sbin/nginx -g"     9 seconds ago   nginx-6
#根据镜像创建容器,创建时候,不添加执行命令,覆盖cmd的参数 -g "daemon off;"
:~/docker/images/nginx$ docker run  --name nginx-7 -d ubuntu-nginx:v0.5 -g "daemon off;"

#查看效果
itcast@itcast-virtual-machine:~/docker/images/nginx$ docker ps -a 
CONTAINER ID    IMAGE               COMMAND                  CREATED         NAMES
e5addad86ef5    ubuntu-nginx:v0.5   "/usr/sbin/nginx -g …"   5 seconds ago   nginx-7
#注释:
#任何docker run设置的命令参数或者CMD指令的命令,都将作为ENTRYPOINT 指令的命令参数,追加到ENTRYPOINT指令之后

1.5 文件编辑指令详解

ADD
#ADD
#格式:
    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"]
#解释:
	# 将宿主机文件拷贝到容器目录中
  	# 如果宿主机文件是可识别的压缩包, 会进行解压缩 -> tar
  	ADD 宿主机文件 容器目录/文件
  	
#	ADD ["宿主机文件", "容器目录"]
   - 宿主机文件一般放到Dockerfile对应的目录中
   - 容器目录, 有可能存在, 有可能不存在
    	- 存在: 直接拷贝到容器目录
      - 不存在: 先在容器中创建一个, 再拷贝
  ADD ["a.txt", "/home/go/a.txt"]
   - 第二个参数如果指定的是一个文件名
     - 这个文件存在: 直接覆盖
     - 不存在: 直接拷贝
#ADD实践:
    #拷贝普通文件
    :~/docker/images/nginx$ vim Dockerfile 
    
    #Dockerfile文件内容
    
    # 构建一个基于ubuntu的docker定制镜像
    # 基础镜像
    FROM ubuntu
    # 镜像作者
    MAINTAINER panda kstwoak47@163.com
    # 执行命令
    ADD ["sources.list","/etc/apt/sources.list"]
    RUN apt-get clean
    RUN apt-get update
    RUN apt-get install nginx -y
    # 对外端口
    EXPOSE 80
 
    #构建镜像
    :~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.6 .
    
    #根据镜像创建容器,创建时候,不添加执行命令进入容器查看效果
    docker run  --name nginx-8 -it ubuntu-nginx:v0.6
    
    #拷贝压缩文件
    tar zcvf this.tar.gz ./*
    #Dockerfile文件内容
    ...
    # 执行命令
    ...
    # 增加文件
    ADD ["linshi.tar.gz","/nihao/"]
    ...
    #构建镜像
    :~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.7 .
    #根据镜像创建容器,创建时候,不添加执行命令进入容器查看效果
    docker run --name nginx-9 -it ubuntu-nginx:v0.7
    :~/docker/images/nginx$ docker run --name nginx-9 -it ubuntu-nginx:v0.7
COPY
#COPY
    #格式:
    COPY <src>... <dest>
    COPY ["<src>",... "<dest>"]
    #解释:
    #COPY 指令和ADD 指令功能和使用方式类似。只是COPY 指令不会做自动解压工作。
    #单纯复制文件场景,Docker 推荐使用COPY
#COPY实践
    #修改Dockerfile文件内容:
    # 构建一个基于ubuntu的docker定制镜像
    # 基础镜像
    FROM ubuntu
    # 镜像作者
    MAINTAINER panda kstwoak47@163.com
    # 执行命令
ADD ["sources.list","/etc/apt/sources.list"]
RUN apt-get clean
RUN apt-get update
RUN apt-get install nginx -y
COPY ["index.html","/var/www/html/"]
# 对外端口
EXPOSE 80
#运行时默认命令 
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
index.html 文件内容:
<h1>hello world </h1>
<h1>hello docker </h1>
<h1>hello nginx</h1>
 
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.8 .
#根据镜像创建容器,创建时候,不添加执行命令
:~/docker/images/nginx$ docker run  --name nginx-10 -itd ubuntu-nginx:v0.8
#查看nginx-10信息
:~/docker/images/nginx$docker inspect  nginx-10
#浏览器访问nginx查看效果    

VOLUME

#VOLUME
    #格式:
    VOLUME ["/data"]
    #解释:
    #VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点
    #通过VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。
    #举例:
    VOLUME ["/var/lib/tomcat7/webapps/"]

VOLUME实践

#VOLUME实践
#修改Dockerfile文件内容:
#将COPY替换成为VOLUME
:~/docker/images/nginx$vim Dockerfile
VOLUME ["/helloworld/"]
...
#构建镜像
:~/docker/images/nginx$docker build -t ubuntu-nginx:v0.9 .
#创建数据卷容器
:~/docker/images/nginx$docker run -itd --name nginx-11 ubuntu-nginx:v0.9
#查看镜像信息
:~/docker/images/nginx$docker inspect nginx-11
#验证操作
:~/docker/images/nginx$docker run -itd --name vc-nginx-1 --volumes-from nginx-11 nginx
:~/docker/images/nginx$docker run -itd --name vc-nginx-2 --volumes-from nginx-11 nginx
#进入容器1
:~/docker/images/nginx$docker exec -it vc-nginx-1 /bin/bash
:/# echo 'nihao itcast' > helloworld/nihao.txt
#进入容器2
:~/docker/images/nginx$ docker exec -it vc-nginx-2 /bin/bash
:/# cat helloworld/nihao.txt

1.6 环境指令详解

ENV
#ENV
    #格式:
    ENV <key> <value>                    (一次设置一个环节变量)
    ENV <key>=<value> ...                (一次设置一个或多个环节变量)
    ENV HELLO 12345
  	ENV HELLO=12345
  	ENV HELLO=12345 WORLD=12345 NIHAO=12345
#解释:
#设置环境变量,可以在RUN 之前使用,然后RUN 命令时调用,容器启动时这些环境变量都会被指定

ENV实践

#ENV实践:
    #命令行创建ENV的容器
    :~$ docker run -e NIHAO="helloworld" -itd --name ubuntu-111 ubuntu /bin/bash
    #进入容器ubuntu-111
    :~$ docker exec -it ubuntu-111 /bin/bash
    :/# echo $NIHAO
    
    #修改Dockerfile文件内容:
    #在上一个Dockerfile 文件内容基础上,在RUN 下面增加一个ENV
    ENV NIHAO=helloworld
    ...
    #构建镜像
    docker build -t ubuntu-nginx:v0.10 .
    
    #根据镜像创建容器,创建时候,不添加执行命令
    docker run  --name nginx-12 -itd ubuntu-nginx:v0.10
    docker exec -it nginx-12 /bin/bash
    echo $NIHAO
WORKDIR
#WORKDIR
    #格式:
    WORKDIR /path/to/workdir (shell 模式)
    #解释:
    #切换目录,为后续的RUN、CMD、ENTRYPOINT 指令配置工作目录。相当于cd
    #可以多次切换(相当于cd 命令),
    #也可以使用多个WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如
    #举例:
    WORKDIR /a
    WORKDIR b
    WORKDIR c
    RUN pwd
    #则最终路径为/a/b/c

WORKDIR实践

#WORKDIR实践:
    #修改Dockerfile文件内容:
    # 在上一个Dockerfile 文件内容基础上,在RUN 下面增加一个WORKDIR
    WORKDIR /nihao/itcast/
    RUN ["touch","itcast1.txt"]
    WORKDIR /nihao
    RUN ["touch","itcast2.txt"]
    WORKDIR itcast
    RUN ["touch","itcast3.txt"]
    ...
    #构建镜像
    :~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.11 .
    #根据镜像创建容器,创建时候,不添加执行命令
    docker run  --name nginx-13 -itd ubuntu-nginx:v0.11
    #进入镜像
    docker exec -it nginx-13 /bin/bash

USER与ARG

#USER
    #格式:
    USER daemon
    #解释:
    #指定运行容器时的用户名和UID,后续的RUN 指令也会使用这里指定的用户。
    #如果不输入任何信息,表示默认使用root 用户

#ARG
    #格式:
    ARG <name>[=<default value>]
    #解释:
    #ARG 指定了一个变量在docker build 的时候使用,可以使用--build-arg <varname>=<value>来指定参数的值,不过
    #如果构建的时候不指定就会报错。

1.7 触发器指令详解

触发器指令

ONBUILD
#格式:
    ONBUILD [command]
#解释:
    #当一个镜像A被作为其他镜像B的基础镜像时,这个触发器才会被执行,
    #新镜像B在构建的时候,会插入触发器中的指令。
    #使用场景对于版本控制和方便传输,适用于其他用户。
    
  # 原始镜像 -> 纯净版
  	-> 修改 ONBUILD ["echo", "hello,linux"]
  	   
  # 基于原始镜像制作新镜像 -> 镜像A
  	-> 启动镜像A -> 不会输出hello, linux
  	
  # 基于镜像A制作了镜像B
  	-> 启动镜像B -> 会输出 hello, linux

触发器实践

#编辑Dockerfile
:~/docker/images/nginx$ vim Dockerfile 
#内容如下:
# 构建一个基于ubuntu的docker定制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER panda kstwoak47@163.com
# 执行命令
ADD ["sources.list","/etc/apt/sources.list"] 
RUN apt-get clean
RUN apt-get update 
RUN apt-get install nginx -y 
#触发器
ONBUILD COPY ["index.html","/var/www/html/"]
# 对外端口
EXPOSE 80
#运行时默认命令 
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
 
#构建镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.12 .
 
#根据镜像创建容器,
:~/docker/images/nginx$docker run -p 80 --name nginx-14 -itd ubuntu-nginx:v0.12
:~/docker/images/nginx$docker ps
#查看镜像信息
:~/docker/images/nginx$ docker inspect ubuntu-nginx:v0.12  
#访问容器页面,是否被更改
:~/docker/images/nginx$ docker inspect nginx-14

#构建子镜像Dockerfile文件
FROM ubuntu-nginx:v0.12
MAINTAINER panda kstwoak47@163.com
EXPOSE 80
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
 
#构建子镜像
:~/docker/images/nginx$ docker build -t ubuntu-nginx:v0.13 .
#根据镜像创建容器,
docker run -p 80 --name nginx-15 -itd ubuntu-nginx:v0.13
#查看镜像信息
:~/docker/images/nginx$ docker inspect ubuntu-nginx:v0.13
docker ps
#访问容器页面,是否被更改

1.8 Dockerfile构建缓存

我们第一次构建很慢,之后的构建都会很快,因为他们用到了构建的缓存。

#取消缓存:
docker build --no-cache -t [镜像名]:[镜像版本][Dockerfile位置]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值