Docker极速入门掌握基本概念和用法

1、Docker概念

1.1什么是docker

  • Docker是一个快速交付应用、运行应用的技术,具备以下优势
    1. 可将程序及其依赖、运行环境一起打包为一个镜像,可以迁移到任意Linux操作系统
    2. 运行时利用沙箱机制形成隔离容器,各个应用互不干扰
    3. 启动、移除都可以通过一行命令完成,方便快捷
  • Docker如何解决大型项目依赖关系复杂,不同组件依赖的兼容性问题?
    • Docker允许开发中将应用、依赖、函数库、配置一起打包,形成可移植镜像
    • Docker应用运行在容器中,使用沙箱机制,相互隔离
  • Docker如何解决开发、测试、生产环境有差异的问题?
    • Docker景象中包含完整运行环境,包括系统函数库,仅依赖系统的Linux内核,因此可以在任意Linux操作系统上运行

 1.2Docker与虚拟机的区别

  • Docker可以让一个应用在任何操作系统中都十分方便的运行,而我们以前接触的虚拟机,也能在一个操作系统中,运行另外一个操作系统,保护系统中的任何应用

  • 二者有什么差异呢?

    • 虚拟机(virtual machine)是在操作系统中模拟硬件设备,然后运行另一个操作系统。例如在Windows系统中运行CentOS系统,就可以运行任意的CentOS应用了
    • Docker仅仅是封装函数库,并没有模拟完整的操作系统
  • 对比来看
特性 Docker 虚拟机
性能 接近原生 性能较差
硬盘占用 一般为MB 一般为GB
启动 秒级 分钟级

1.3Docker架构

  • 镜像:
    • 将应用程序及其依赖、环境、配置打包在一起
  • 容器:
    • 镜像运行起来就是容器,一个镜像可以运行多个容器
  • Docker结构:
    • 服务端:接受命令或远程请求,操作镜像或容器
    • 客户端:发送命令或者请求到Docker服务端
  • DockerHub:
    • 一个镜像托管的服务器,类似的还有阿里云镜像服务,统称为DockerRegistry

  • Docker是一个CS架构的程序,由两部分组成
    • 服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等
    • 客户端(client):通过命令或RestAPI向Docker服务端发送指令,可以在本地或远程向服务端发送指令

 2、Docker基本操作

2.1镜像制作

镜像名称

  • 首先来看下镜像的名称组成:
    • 镜像名称一般分为两部分:[repository]:[tag]

    例如mysql:5.7,这里的mysql就是repository,5.7就是tag,合在一起就是镜像名称,代表5.7版本的MySQL镜像

    • 在没有指定tag时,默认是latest,代表最新版本的镜像,例如mysql:latest

镜像命令

案例一

需求:从DockerHub中拉取一个Nginx镜像并查看

1.首先我们取镜像仓库(例如DockerHub)中搜索Nginx镜像

2.根据查看到的镜像名称,拉取自己需要的镜像。若直接通过命令:docker pull nginx则是拉取最新版本的nginx镜像

3.通过命令docker images查看拉取到的镜像

案例二

需求:利用docker save将nginx镜像导出磁盘,然后在通过docker load加载回来

1.命令格式 

docker save -o [保存的目标文件名称] [镜像名称]

docker load -i [镜像压缩文件名]

2.使用docker save导出镜像到磁盘,随后使用ls命令可以查看到nginx.tar文件

docker save -o nginx.tar nginx:latest

3.使用docker load加载镜像,在此之前,我们使用命令删除本地nginx镜像

docker rmi nginx:latest ## rmi是remove image的缩写

加载本地文件

docker load -i nginx.tar

2.2容器操作

相关命令

  • docker run:创建并运行一个容器,处于运行状态
  • docker pause:让一个运行的容器暂停
  • docker unpause:让一个容器从暂停状态恢复运行
  • docker stop:停止一个运行的容器
  • docker start:让一个停止的容器再次运行
  • docker rm:删除一个容器
  • 查看容器状态:

    • docker ps
    • docker ps -a 查看所有容器,包括已停止的
  • 查看容器日志的命令

    • docker logs
    • 添加-f参数可以持续查看日志

 相关状态

  • 运行:进程正常运行
  • 暂停:容器内的进程挂起,容器关联的内存暂存起来,然后CPU不再执行这个进程
  • 停止:进程终止,回收进程占用的内存、CPU等资源

案例一

docker run --name containerName -p 80:80 -d nginx

  • 命令解读

    • docker run:创建并运行一个容器
    • --name:给容器起一个名字,例如叫做myNginx
    • -p:将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口
    • -d:后台运行容器
    • nginx:镜像名称,例如nginx

这里的-p参数,是将容器端口映射到宿主机端口 默认情况下,容器是隔离环境,我们直接访问宿主机的80端口,肯定访问不到容器中的nginx 现在,容器的80端口和宿主机的80端口关联了起来,当我们访问宿主机的80端口时,就会被映射到容器的80端口,这样就能访问nginx了 那我们再浏览器输入虚拟机ip:80就能看到nginx默认页面了

案例二

1、启动容器

docker run --name myNginx -p 80:80 -d nginx

2、进入刚刚创建好的nginx容器

docker exec -it myNginx bash

  • 命令解读
    • docker exec:进入容器内部,执行一个命令
    • -it:给当前进入的容器创建一个标准输入、输出终端,允许我们与容器交互
    • myNginx:要进入的容器名称
    • bash:进入容器后执行的命令,bash是一个linux终端交互命令

退出容器:exit

3、进入nginx的HTML所在目录

  • 容器内部会模拟一个独立的Linux文件系统,看起来就如同一个linux服务器一样,nginx的环境、配置、运行文件全部都在这个文件系统中,包括我们要修改的html文件
  • 查看DockerHub网站中的nginx页面,可以知道nginx的html目录位置在/usr/share/nginx/html

我们执行命令进入到该目录

cd /usr/share/nginx/html

查看目录下的文件

4、修改index.html的内容

  • 容器内没有vi命令,无法直接修改,我们使用下面的命令来修改

sed -i -e 's#Welcome to nginx#Welcome To My Blog#g' index.html

5、在浏览器访问自己的虚拟机ip:80

2.3数据卷

  • 在之前的nginx案例中,修改nginx的html页面时,需要进入nginx内部。并且因为没有编译器,修改文件也很麻烦,这就是容器与数据(容器内文件)耦合带来的后果,如果我们另外运行一台新的nginx容器,那么这台新的nginx容器也不能直接使用我们修改好的html文件,具有很多缺点
    1. 不便于修改:当我们要修改nginx的html内容时,需要进入容器内部修改,很不方便
    2. 数据不可服用:由于容器内的修改对外是不可见的,所有的修改对新创建的容器也是不可复用的
    3. 升级维护困难:数据在容器内,如果要升级容器必然删除旧容器,那么旧容器中的所有数据也跟着被删除了(包括改好的html页面)
  • 要解决这个问题,必须将数据和容器解耦,这就要用到数据卷了

什么是数据卷

数据卷(volume)是一个虚拟目录,指向宿主机文件系统中的某个目录

一旦完成数据卷挂载,对容器的一切操作都会作用在对应的宿主机目录了。这样我们操作宿主机的/var/lib/docker/volumes/html目录,就等同于操作容器内的/usr/share/nginx/html目录了

数据卷操作命令

docker volume [COMMAND]

  • docker volume命令是数据卷操作,根据命令后跟随的command来确定下一步的操作
    • create:创建一个volume
    • inspect:显示一个或多个volume的信息
    • ls:列出所有的volume
    • prune:删除未使用的volume
    • rm:删除一个或多个指定的volume

创建和查看数据集

注意:若已经进入了容器的话要先退出

需求:创建一个数据卷,并查看数据卷在宿主机的目录位置

1、创建数据卷

docker volume create html

2、查看所有数据

docker volume ls

 3、查看数据卷详细信息卷

docker volume inspect html

结果 

可以看到我们创建的html这个数据卷关联的宿主机目录为/var/lib/docker/volumes/html/_data 

挂载数据卷 

  • 我们在创建容器时,可以通过-v参数来挂载一个数据卷到某个容器内目录,命令格式如下

docker run \

        -- name myNginx \

        -v html:/root/html \

        -p 8080:80 \

        nginx \ 

 这里的-v就是挂载数据卷的命令

  • -v html:/root/html:把html数据卷挂载到容器内的/root/html这个目录
  • docker run的命令中通过-v参数挂载文件或目录到容器中

    • -v [volume名称]:[容器内目录]
    • -v [宿主机文件]:[容器内文件]
    • -v [宿主机目录]:[容器内目录]

案例一

需求:创建一个nginx容器,修改容器内的html目录的index.html内容
分析:上个案例中,我们进入nginx容器内部,已经知道了nginx的html目录所在位置/usr/share/nginx/html,我们需要把这个目录挂载到html这个数据卷上,方便操作其中的内容
提示:运行容器时,使用-v参数挂载数据卷

1、创建容器并挂载数据卷到容器内的HTML目录

docker run --name myNginx -v html:/usr/share/nginx/html -p 80:80 -d nginx

2、进入html数据卷所在位置,并修改HTML内容

## 查看数据卷位置 docker volume inspect html

## 进入该目录

cd /var/lib/docker/volumes/html/_data

## 修改文件

vi index.html

## 也可以在FinalShell中使用外部编译器(例如VSCode)来修改文件

案例二

容器不仅仅可以挂载数据卷,也可以直接挂载到宿主机目录上,关系如下

  • 带数据卷模式:宿主机目录 --> 数据卷 --> 容器内目录
  • 直接挂载模式:宿主机目录 --> 容器内目录

目录挂载和数据卷挂载的语法是类似的

  • -v [宿主机目录]:[容器内目录]
  • -v [宿主机文件]:[容器内文件]

 需求:创建并运行一个MySQL容器,将宿主机目录直接挂载到容器

1、从DockerHub中拉取一个MySQL的镜像

docker pull mysql

 2、创建目录/tmp/mysql/data

mkdir -p /tmp/mysql/data

3、创建目录/tmp/mysql/conf,将myCnf.cnf文件上传到/tmp/mysql/conf

mkdir -p /tmp/mysql/conf

myCnf.cnf

[mysqld]

skip-name-resolve

character_set_server=utf8

datadir=/var/lib/mysql

server-id=1000

4、去DockerHub中查阅资料,找到mysql容器内的conf目录和data目录的位置
容器中conf目录的位置是:/etc/mysql/conf.d
容器中存储数据的目录为:/var/lib/mysql

5、创建并运行MySQL容器,要求

  • 挂载/tmp/mysql/data到mysql容器内数据存储目录
  • 挂载/tmp/mysql/conf/myCnf.cnf到mysql容器的配置文件
  • 设置MySQL密码
docker run \
--name mysql \ 
-e MYSQL_ROOT_PASSWORD=root \
-v /tmp/mysql/conf:/etc/mysql/conf.d \
-v /tmp/mysql/data:/var/lib/mysql \
-p 3306:3306 \
-d \
mysql

3、Dockerfile自定义镜像

3.1镜像结构

  • 镜像是将应用程序及其需要的系统函数库,环境、配置、依赖打包而成

  • 以MySQL为例,来看看它的镜像组成结构

  • 简单来说,镜像就是在系统函数库、运行环境的基础上,添加应用程序文件、配置文件、依赖文件等组合,然后编写好启动脚本打包在一起形成的文件

  • 我们要构建镜像,其实就是实现上述打包的过程

3.2Dockerfile语法

  • 构建自定义镜像时,并不需要一个个文件去拷贝,打包。
  • 我们只需要告诉Docker我们的镜像组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、启动脚本是什么,将来Docker会帮助我们构建镜像
  • 而描述上述信息的就是Dockerfile文件。
  • Dockerfile就是一个文本文件,其中包含一个个指令(Instruction),用指令说明要执行什么操作来构建镜像,每一个指令都会形成一层Layer。
指令 说明 示例
FROM 指定基础镜像 FROM centos:6
ENV 设置环境变量,可在后面指令使用 ENV key value
COPY 拷贝本地文件到镜像的指定目录 COPY ./mysql-5.7.rpm /tmp
RUN 执行Linux的shell命令,一般是安装过程的命令 RUN yum install gcc
EXPOSE 指定容器运行时监听的端口,是给镜像使用者看的 EXPOSE 8080
ENTRYPOINT 镜像中应用的启动命令,容器运行时调用 ENTRYPOINTjava -jar xxjar

3.3构建Java项目

3.3.1自定义jdk项目

需求:基于Ubuntu镜像构建一个新镜像,运行一个Java项目

1.创建一个空文件夹docker-demo

mkdir /tmp/docker-demo

2.将docker-demo.jar文件拷贝到docker-demo这个目录

3.拷贝jdk8.tar.gz文件到docker-demo这个目录

4.在docker-demo目录下新建Dockerfile,并写入以下内容

## 指定基础镜像
FROM ubuntu:16.04

## 配置环境变量,JDK的安装目录
ENV JAVA_DIR=/usr/local

## 拷贝jdk的到JAVA_DIR目录下
COPY ./jdk8.tar.gz $JAVA_DIR/

## 安装JDK
RUN cd $JAVA_DIR && tar -xf ./jdk8.tar.gz && mv ./jdk1.8.0_44 ./java8

## 配置环境变量
ENV JAVA_HOME=$JAVA_DIR/java8
ENV PATH=$PATH:$JAVA_HOME/bin

## 拷贝java项目的包到指定目录下,我这里是/tmp/app.jar
COPY ./docker-demo.jar /tmp/app.jar

## 暴露端口,注意这里是8090端口,如果你之前没有关闭防火墙,请关闭防火墙或打开对应端口,云服务器同理
EXPOSE 8090

## 入口,java项目的启动命令
ENTERPOINT java -jar /tmp/app.jar

 5.在docker-demo目录下使用docker build命令构建镜像

docker build -t docker_demo:1.0 .

 6.使用docker images命令,查看镜像

[root@localhost docker-demo]## docker images
REPOSITORY    TAG       IMAGE ID       CREATED              SIZE
docker_demo   1.0       c8acd2dd02cf   About a minute ago   722MB
redis         latest    29ab4501eac3   2 days ago           117MB
nginx         latest    3964ce7b8458   5 days ago           142MB
ubuntu        16.04     b6f507652425   15 months ago        135MB
mysql         5.7.25    98455b9624a9   3 years ago          372MB

7.创建并运行一个docker_demo容器

 docker run --name testDemo -p 8090:8090 -d docker_demo:1.0

8、访问测试

3.3.2基于java8构建java项目

我们每次构建Java项目的镜像的时候,都需要安装JDK并配置环境变量,所以我们可以找一个已经安装好了JDK的基础镜像,然后在其基础上来构建我们的Java项目的镜像

 需求:基于java:8-alpine镜像,将一个Java项目构建为镜像

1、新建一个空目录(或者继续使用/tmp/docker-demo目录)

2、将docker-demo.jar复制到该目录下(继续使用刚刚的目录就不用管)

3、在目录中新建一个文件,命名为Dockerfile,并编写该文件(修改为如下样子就好)

## 将openjdk:8作为基础镜像
FROM openjdk:8
## 拷贝java项目的包到指定目录下,我这里是/tmp/app.jar
COPY ./docker-demo.jar /tmp/app.jar
## 暴露端口
EXPOSE 8090
## 入口
ENTRYPOINT java -jar /tmp/app.jar

4、构建镜像

docker build -t docker_demo:2.0 .

5、 创建并运行一个docker_demo容器(在此之前停止之前的docker_demo容器)

docker run --name testDemo02 -p 8090:8090 -d docker_demo:2.0

 6、浏览器访问地址

4、Docker-Compose

4.1初识DockerCompose

  • Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行,格式如下
version: "3.8"
  services:
    ## docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -v /tmp/mysql/data:/var/lib/mysql -v /tmp/mysql/conf/myCnf.cf:/etc/mysql/conf.d/myCnf.cnf -d mysql:5.7.25
    mysql:  ## 对应docker run中的 --name
      image: mysql:5.7.25 ## 对应docker run中最后声明的镜像
      enviroment:   ## 对应docker run中的 -e MYSQL_ROOT_PASSWIRD=root
        MYSQL_ROOT_PASSWORD: root
      volumes: ## 对应docker run中的 -v /tmp/mysql/data:/var/lib/mysql
        - "/tmp/mysql/data:/var/lib/mysql"
        - "/tmp/mysql/conf/myCnf.cf:/etc/mysql/conf.d/myCnf.cnf"
    ## 这里并不需要-d参数来后台运行,因为此种方法默认就是后台运行
    ## 同时也不需要暴露端口,在微服务集群部署中,MySQL仅仅是供给给集群内的服务使用的,所以不需要对外暴露端口

    ## 临时构建镜像并运行,下面的配置文件包含了docker build和docker run两个步骤
    ## docker build -t web:1.0 .
    ## docker run --name web -p 8090:8090 -d web:1.0
    web:
      build: .
      ports:
        - "8090:8090"
  • 上面的Compose文件就描述一个项目,其中包含两个容器:
    • mysql:一个基于mysql:5.7.25镜像构建的容器,并且挂载了两个项目
    • web:一个基于docker build临时构建的镜像容器,映射端口为8090
  • DockerCompose的详细语法请参考官网:Overview | Docker Docs
  • 其实DockerCompose文件可以看做是将多个docker run命令写到一个文件,只是语法稍有差异

4.2安装DockerCompose

  • 在Linux下使用命令下载
## 安装
curl -L https://github.com/docker/compose/releases/download/1.23.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  • 修改文件权限
chmod +x /usr/local/bin/docker-compose
  • Base自动补全命令
curl -L https://raw.githubusercontent.com/docker/compose/1.29.1/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose

如出现错误Failed connect to raw.githubusercontent.com:443; Connection refused,需要修改自己的hosts文件

echo "199.232.68.133 raw.githubusercontent.com" >> /etc/hosts

4.3部署微服务集群

需求:将之前学习的cloud-demo微服务集群利用DockerCompose部署

  • 实现思路
    1. 编写docker-compose文件
    2. 修改自己的cloud-demo项目,将其中的数据库、nacos地址,都重命名为docker-compose中的服务名
    3. 使用maven打包工具,将项目中的每个微服务都打包为app.jar(打包名与Dockerfile中一致即可)
    4. 将打包好的app.jar拷贝到cloud-demo中的每一个对应的子目录中,编写Dockerfile文件
    5. 将cloud-demo上传至虚拟机,利用docker-compose up -d来部署

compose文件

  • 针对我们之前写的cloud-demo,来编写对应的docker-compose文件
version: "3.2"

services:
  nacos:
    image: nacos/nacos-server
    environment:
      MDOE: standalone
    ports:
      - "8848:8848"
    mysql:
      image: mysql:5.7.25
      environment:
        MYSQL_ROOT_PASSWORD: root
      volumes:
        - "$PWD/mysql/data:/var/lib/mysql"  ## 这里的$PWD是执行linux命令,获取当前目录
        - "$PWD/mysql/conf:/etc/mysql/conf.d"
    userservice:
      build: ./user-service
    orderservice:
      build: ./order-service
    gateway:
      build: ./gateway
      poets:
        - "10010:10010"
  • 其中包含了5个服务:
    1. nacos:作为注册中心和配置中心
      • image: nacos/nacos-server:基于nacos/nacos-server镜像构建
      • environment: 环境变量
        • MODE: standalone:单点模式启动
      • ports:端口映射,这里暴露了8848端口
    2. mysql:数据库
      • image: mysql5.7.25:基于5.7.25版本的MySQL镜像构建
      • environment:环境变量
        • MYSQL_ROOT_PASSWORD: root:设置数据库root账户密码为root
      • volumes:数据卷挂载,这里挂载了mysql的data和conf目录
    3. userservice:基于Dockerfile临时构建,userservice不需要暴露端口,网关才是微服务的入口,如果暴露了userservice的端口,那么网关的身份认证,权限校验就形同虚设了
    4. orderservice:基于Dockerfile临时构建,不需要暴露端口,理由同上
    5. gateway:基于Dockerfile临时构建,网关需要暴露端口,它是其他微服务的入口

修改微服务配置

  • 使用Docker Compose部署时,所有的服务之间都可以用服务名互相访问,那我们现在就需要修改我们cloud-demo中的yml配置文件,如下

bootstrap.yml

spring:
  cloud:
    nacos:
      ## server-addr: localhost:80 #Nacos地址
      server-addr: nacos:8848 ## 使用compose中的服务名来互相访问,用nacos替换localhost
      config:
        file-extension: yaml ## 文件后缀名

application.yml

server:
  port: 8081
spring:
  datasource:
    ## url: jdbc:mysql://mysql:3306/cloud_user?useSSL=false
    url: jdbc:mysql://mysql:3306/cloud_user?useSSL=false ## 这里同理,使用mysql替换localhost
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

打包

用maven工具进行打包

server:
  port: 8081
spring:
  datasource:
    ## url: jdbc:mysql://mysql:3306/cloud_user?useSSL=false
    url: jdbc:mysql://mysql:3306/cloud_user?useSSL=false ## 这里同理,使用mysql替换localhost
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

拷贝jar包到部署目录,并编写Dockerfile文件

Gateway

FROM openjdk:8
COPY ./app.jar /tmp/app.jar
ENTERPOINT java -jar /tmp/app.jar

order-service、user-servier

FROM openjdk:8
COPY ./app.jar /tmp/app.jar
ENTERPOINT java -jar /tmp/app.jar
  • 最终的目录结构如下
    • cloud-demo
      • gateway
        • app.jar
        • Dockerfile.yml
      • order-service
        • app.jar
        • Dockerfile.yml
      • user-service
        • app.jar
        • Dockerfile.yml
      • mysql
        • data
        • conf
      • docker-compose.yml

部署

  • 将cloud-demo上传到虚拟机,进入目录,执行以下命令

docker-compose up -d

docker-compose logs -f

  • 启动之后查看日志,会发现日志中报错 com.alibaba.nacos.api.exception.NacosException: failed to req API:/nacos/v1/ns/instance/list after all servers([nacos:8848]) tried: java.net.ConnectException: Connection refused (Connection refused)

阿里巴巴nacos连接失败,其原因是userservice在nacos之前启动了,而nacos启动太慢了,userservice注册失败,而且也没有重试机制(等nacos启动完成后,重试注册,就可以避免这个问题)

  • 所以建议nacos单独先启动,其他服务后启动,我这里的解决方案是重启另外三个服务
  • 重启gateway userservice orderservice服务

docker-compose restart gateway userservice orderserivce

5、Docker镜像仓库

5.1搭建私有镜像仓库

5.1.1配置Docker信任地址
  • 我们的私服采用的是http协议,默认不被Docker信任,所以需要做一个配置:
## 打开要修改的文件
vi /etc/docker/daemon.json
## 添加内容:
"insecure-registries":["http://xxxx:8080"]
## 重加载
systemctl daemon-reload
## 重启docker
systemctl restart docker

5.1.2带图形化界面版本

  • 使用DockerCompose部署带有图象界面的DockerRegistry,命令如下:
version: '3.0'
services:
  registry:
    image: registry
    volumes:
      - ./registry-data:/var/lib/registry
  ui:
    image: joxit/docker-registry-ui:static
    ports:
      - 8080:80
    environment:
      - REGISTRY_TITLE=Kyle's Blog私有仓库
      - REGISTRY_URL=http://registry:5000
    depends_on:
      - registry

随后打开浏览器访问http://xxxx:8080/, 就能看到带图形化界面的镜像仓库了

5.2推送、拉取镜像

推送镜像到私有镜像服务必须先tag,步骤如下

1.重新tag本地镜像,名称前缀为私有仓库的地址:xxxx:8080/

docker tag nginx:latest 192.168.128.130:8080/nginx:1.0

2.推送镜像

docker push 192.168.128.130:8080/nginx:1.0

3. 拉取镜像

docker push xxxx:8080/nginx:1.0

参考文章:Docker | Kyle's Blog (cyborg2077.github.io)

相关推荐

  1. git的基本概念

    2024-02-05 02:08:01       26 阅读
  2. Numpy入门学习

    2024-02-05 02:08:01       31 阅读
  3. Docker概念

    2024-02-05 02:08:01       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-05 02:08:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-05 02:08:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-05 02:08:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-05 02:08:01       18 阅读

热门阅读

  1. Vue3都做了哪些改进升级,看这一篇就够了

    2024-02-05 02:08:01       40 阅读
  2. 【从浅到深的算法技巧】堆排序,应用

    2024-02-05 02:08:01       25 阅读
  3. 阿里云入门

    2024-02-05 02:08:01       32 阅读
  4. K8s之configMap

    2024-02-05 02:08:01       27 阅读
  5. 常见code review问题

    2024-02-05 02:08:01       31 阅读
  6. MySQL中SQL查询语句优化

    2024-02-05 02:08:01       35 阅读
  7. 开源协议介绍

    2024-02-05 02:08:01       36 阅读
  8. 【华为机试】2023年真题C卷(python)-字符串拼接

    2024-02-05 02:08:01       39 阅读
  9. Docker 大纲

    2024-02-05 02:08:01       29 阅读
  10. 【递归】 92. 反转链表 II

    2024-02-05 02:08:01       33 阅读