Docker - Explicación detallada y uso de Docker

Antes de hablar de Docker, hablemos de los servidores tradicionales

El servidor independiente tradicional es un dispositivo de hardware independiente, que puede entenderse como una computadora de alta configuración ubicada en la sala de cómputo; tiene procesador independiente, memoria, disco duro, ancho de banda y otros recursos, y varios sistemas operativos y configura varios entornos.

Desventajas de este servidor:

1. Alto costo (costo de tiempo, costo de capital)

2. La migración de aplicaciones es engorrosa. Es necesario volver a comprar el servidor, instalar el sistema operativo, configurar el entorno operativo e implementar la aplicación.

Por lo tanto, ha surgido la tecnología de virtualización, que se divide principalmente en

Virtualización de hardware (virtualización a nivel de hardware)

Virtualización del sistema operativo (os-level-virtualization)

La virtualización de hardware es una tecnología de virtualización que se ejecuta en hardware. El núcleo de la tecnología es el hipervisor. El hipervisor es una capa de software que se ejecuta en el servidor físico básico, que puede virtualizar recursos de hardware, como CPU, disco duro, memoria, etc., y luego El sistema operativo instalado en los recursos virtualizados es la llamada máquina virtual, como VMWare, VirtualBox, etc.

La virtualización del sistema operativo es una tecnología de virtualización que se ejecuta en el sistema operativo. Simula múltiples procesos diferentes que se ejecutan en un sistema operativo y los encapsula en un contenedor cerrado, también conocido como tecnología de contenedorización, como Docker.

VM: el hipervisor se utiliza para proporcionar una plataforma de ejecución para máquinas virtuales y administrar el funcionamiento del sistema operativo en cada VM. Cada VM debe tener su propio sistema operativo, aplicaciones y archivos dependientes necesarios, etc.

Contenedor Docker: use el motor Docker para la programación y el aislamiento, lo que mejora la utilización de recursos y permite que se ejecuten más instancias de contenedor con la misma capacidad de hardware; cada contenedor tiene su propio espacio de usuario aislado

En comparación con la VM, el contenedor Docker, como método de virtualización liviano, tiene las siguientes ventajas significativas en términos de aplicación:

1. Los contenedores Docker se pueden iniciar y detener rápidamente en segundos, lo que mejora significativamente en comparación con las máquinas virtuales tradicionales

2. Los contenedores Docker tienen requisitos bajos de recursos del sistema y miles de contenedores Docker pueden ejecutarse en el mismo host al mismo tiempo. Los contenedores Docker facilitan a los usuarios obtener y actualizar imágenes de aplicaciones a través de operaciones similares a Git

3. El contenedor Docker realiza la creación automática y la implementación flexible a través del archivo de configuración Dockerfile, lo que mejora la eficiencia del trabajo.

4. Además de ejecutar las aplicaciones en el contenedor Docker, básicamente no consume recursos adicionales del sistema, lo que garantiza el rendimiento de la aplicación y minimiza la sobrecarga del sistema.

La siguiente figura puede comprender intuitivamente la diferencia entre el contenedor Docker y el método tradicional de VM:

1. Introducción a Docker

Docker es un motor contenedor de aplicaciones de código abierto, basado en  el lenguaje Go  y de código abierto de conformidad con el protocolo Apache2.0

Docker permite a los desarrolladores empaquetar sus aplicaciones y dependencias en un contenedor portátil y liviano, que luego se puede distribuir a cualquier máquina Linux popular y también se puede virtualizar.

Docker se ha dividido en CE (Community Edition: Community Edition) y EE (Enterprise Edition: Enterprise Edition) desde la versión 17.03. Usamos Community Edition.

Docker es una solución ligera de virtualización del sistema operativo. Docker se basa en la tecnología de contenedor Linux (LXC), que es un paquete estandarizado de software y entornos a largo plazo. Las aplicaciones están aisladas entre sí y comparten un sistema operativo.

Docker es compatible con CentOS6 y versiones posteriores

Sitio web oficial de Docker: https://www.docker.com

Código fuente de Github Docker: https://github.com/docker/docker-ce

Almacén espejo de DockerHub: https://hub.docker.com/

2. Instalación e inicio de Docker

1. Instalación de la ventana acoplable

Use el siguiente comando para verificar si Docker está instalado

yum list installed | grep docker 

Comando de instalación simple ( la versión instalada de Docker es antigua, 1.13.x )

//-y 参数表示直接确认,不然会跳出一个确认框,输入Y/N
yum install docker -y

Podemos instalar la versión especificada de Docker de la siguiente manera 

//更新docker的yum源
yum install wget -y

wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

//安装指定版本的docker:
yum install docker-ce-20.10.0 -y

Para la instalación y desinstalación, consulte la documentación más reciente en el sitio web oficial

Instalar Docker Engine en CentOS | Documentación acoplable

Notas de la versión de Docker

Notas de la versión del motor Docker | Documentación acoplable

Después de la instalación, puede utilizar los siguientes tres

//注意:这里两个 横线 ‘--’
docker --version

docker version

docker -v

2. Desinstalar

De acuerdo con el comando view installation docker, puede ver el archivo de instalación de docker y eliminarlo

Primero verifique el estado de ejecución de la ventana acoplable

systemctl status docker 

Si se está ejecutando, desactívelo.

systemctl stop docker

Ver el paquete de archivos docker instalado por yum

 yum list installed |grep docker

 Ver archivos fuente RPM relacionados con Docker

rpm -qa |grep docker

Elimine todos los paquetes docker instalados a su vez, como

yum -y remove docker-ce.x86_64
yum -y remove docker-ce-cli.x86_64
yum -y remove docker-ce-rootless-extras.x86_64
yum -y remove docker-scan-plugin.x86_64

Después de eliminar, puede verificar la fuente de rpm de la ventana acoplable nuevamente

Elimine el archivo de imagen de la ventana acoplable, que se encuentra en el directorio /var/lib/docker de forma predeterminada, use pwd para ver

 

Eliminar el directorio acoplable anterior

rm -rf /var/lib/docker

 3. información del servicio docker

Ver información del sistema docker

docker info

Ver información de ayuda

docker 

 Ver la información de ayuda del comando de un común

docker commond --help

4. Inicie y detenga el servicio docker

puesta en marcha

systemctl start docker 或者
service docker start

 detener

systemctl stop docker 或者
service docker stop

reiniciar

systemctl restart docker 或者
service docker restart

 Ver el estado de ejecución de la ventana acoplable

systemctl status docker 或者
service docker status

Ver el proceso de la ventana acoplable

ps -ef | grep docker

5. Mecanismo operativo Docker

1. Inicie el servicio docker

2. Encuentre la imagen. Antes de ejecutar el contenedor, Docker primero verifica si hay una imagen correspondiente localmente. Si no hay una imagen correspondiente localmente, Docker descargará la imagen del almacén de imágenes.

(1) Busque la imagen que se utilizará en el sitio web oficial de docker hub

Almacén espejo de Docker https://registry.hub.docker.com/

En general, descargue la imagen oficial con el logotipo de la imagen oficial

 (2) Use directamente la línea de comando para usar el comando de búsqueda, como

docker search tomcat

ESTRELLAS: número de estrellas

OFICIAL: si es oficial 

espejo de descarga

// 下面两种方式一样的,默认下载最新版  :latest 即为最新版本
docker pull tomcat
docker pull tomcat:latest

//也可下载其他版本,如
docker pull tomcat:9.0

3. Ejecute la imagen, inicie la imagen para obtener el contenedor correspondiente

// -d 表示后台运行
docker run -d tomcat:9.0
docker run -d docker.io/tomcat
docker run -d 镜像ID

Compruebe si la imagen de Tomcat inicia el contenedor con éxito 

ps -ef | grep tomcat

Ver espejo local

docker images

REPOSITORIO: almacén, como docker.io/tomcat

ETIQUETA: etiqueta de espejo, como la última

ID DE IMAGEN: ID de imagen

CREADO: tiempo de creación

TAMAÑO: tamaño

6. El cliente accede al contenedor

Acceder al contenedor desde el cliente requiere la asignación de puertos; el contenedor docker se comunica con el host en este modo de puente Ayong de manera predeterminada y debe asignar el puerto IP del host al puerto IP del contenedor mediante el parámetro -p

//映射8080 也可以,博主使用的 9090
docker run -d -p 9090:8080 tomcat:9.0
或者
docker run -d -p 9090:8080 镜像ID

7. Ingrese al contenedor Docker

docker exec -it 镜像ID /bin/bash

Salir del contenedor: salir

3. Componentes principales de Docker

Docker utiliza el modo de arquitectura cliente-servidor (C/S) y utiliza la administración remota de API para crear contenedores Docker

Los contenedores de Docker se crean a través de imágenes de Docker

La relación entre imagen y contenedor es similar a la relación entre clase y objeto en la programación orientada a objetos.

Estibador orientado a objetos
imagen de espejo amable
envase objeto

Docker incluye tres elementos centrales

Espejo (Imagen) , contenedor (Contenedor) , almacén (Repositorio)

1. Imagen de espejo

Una imagen de Docker es una plantilla de solo lectura que se utiliza para crear un contenedor de Docker. Es un poco como el disco de instalación del sistema operativo.

La imagen de Docker se puede considerar como un sistema de archivos especial. Además de proporcionar los programas, las bibliotecas, los recursos, la configuración y otros archivos necesarios para que se ejecute el contenedor, también contiene algunos parámetros de configuración preparados para la ejecución (como volúmenes anónimos, variables de entorno, etc.), usuarios, etc.). Las imágenes no contienen datos dinámicos y su contenido no se modifica una vez creadas.

La imagen reflejada se compone de muchas capas de sistemas de archivos, la parte inferior es un sistema de archivos de arranque bootfs, la segunda capa es un sistema de archivos raíz rootfs, el sistema de archivos raíz suele ser algún tipo de sistema operativo, como centos, Ubuntu, en parte superior del sistema de archivos raíz y hay muchas capas de sistemas de archivos, que se apilan para formar una imagen de Docker

 Descripción general de los comandos de duplicación

1. Descarga la imagen

// 下面两种方式一样的,默认下载最新版  :latest 即为最新版本
docker pull tomcat
docker pull tomcat:latest

//也可下载其他版本,如
docker pull tomcat:9.0

2. Ver la imagen descargada

 Latest es la etiqueta de la imagen, que indica la última versión de la imagen.

docker images
或者
docker images tomcat

Obtener el método del espejo

(1) Búsqueda y descarga oficial del almacén acoplable

(2) Construir a través de Dockerfile

 Si no hay una imagen oficial, se construirá a través del archivo Dockerfile

3. Ejecute la imagen para obtener el contenedor.

Acceder al contenedor desde el cliente requiere la asignación de puertos; el contenedor docker se comunica con el host en este modo de puente Ayong de manera predeterminada y debe asignar el puerto IP del host al puerto IP del contenedor mediante el parámetro -p

//映射8080 也可以,博主使用的 9090
docker run -d -p 9090:8080 tomcat:9.0
或者
docker run -d -p 9090:8080 镜像ID

Ver el proceso de Tomcat 

ps -ef | grep tomcat

4. Ver el estado de la imagen del contenedor

//查看运行中容器
docker ps

//查看所有容器
docker ps -a

ID DEL CONTENEDOR: Un identificador único para cada contenedor, generado automáticamente. similar a una clave principal en una base de datos

IMAGEN: El nombre de la imagen utilizada para crear el contenedor

COMANDO: El comando al ejecutar el contenedor

CREADO: cuando se creó el contenedor

ESTADO: El estado de ejecución del contenedor, Hasta 8 meses significa que el contenedor se ha estado ejecutando durante 8 meses
        -creado (creado)
        -reiniciando (reiniciando)
        -ejecutando (ejecutando)
        -eliminando (migración)
        -pausado (pausado)
        -salido ( parado)
        -muerto (muerte)
PUERTOS: Información del puerto abierto por el contenedor.
NOMBRE: el alias del contenedor, que se puede especificar con --name al ejecutar el contenedor para ejecutar docker run

5. Entra en el contenedor

docker exec -it 镜像ID /bin/bash

Salir del contenedor: salir

6. Eliminar la imagen del espejo

docker rmi 镜像ID
或者
docker rmi tomcat:9.0

2. Contenedor

Un contenedor es una instancia de tiempo de ejecución de una imagen. Al igual que lanzar una máquina virtual desde una plantilla de máquina virtual, los usuarios también pueden lanzar uno o más contenedores desde una sola imagen.

Cada contenedor está aislado entre sí para garantizar la seguridad de la plataforma. Un contenedor puede considerarse como una versión simple del sistema Linux.

Docker usa contenedores para ejecutar aplicaciones, la imagen es de solo lectura y el contenedor crea una capa de escritura como la capa superior cuando se inicia

1. Hay dos formas de iniciar el contenedor

(1) Cree un nuevo contenedor basado en la imagen para comenzar

docker run -d tomcat

(2) Reiniciar el contenedor en el estado terminado

docker start 容器id 或 容器名
或者
docker restart 容器id 或 容器名
//查看运行中容器
docker ps

//查看所有容器
docker ps -a

2. Detener el contenedor

docker stop 容器ID 或 容器名

 3. Eliminar el contenedor

Nota:

Al eliminar un contenedor, el contenedor debe estar detenido, de lo contrario, se informará un error

docker stop 容器ID 或 容器名

docker rm 容器ID 或 容器名

4. Entra en el contenedor

docker exec -it 容器ID 或 容器名 /bin/bash

5. Ver más información sobre el contenedor

docker inspect 容器ID 或 容器名

 6. Detenga todos los contenedores en funcionamiento

docker stop $(docker ps -q) 

7. Eliminar todos los contenedores:

docker rm $(docker ps -aq)

8. Un comando para desactivar y eliminar el contenedor

docker stop $(docker ps -q) & docker rm-f $(docker ps -aq)

3. Repositorio

El repositorio es un lugar donde las imágenes se almacenan de forma centralizada. Hay un concepto a distinguir aquí, es decir, el almacén y el servidor de almacén (Registro) son dos cosas diferentes. Al igual que el Docker Hub que mencionamos anteriormente, es un servidor de almacén proporcionado oficialmente por Docker. , pero de hecho A veces no necesitamos distinguir demasiado estos dos conceptos

Docker Hub es el almacén de imágenes central oficial establecido por Docker, y también es el almacén de imágenes predeterminado de Docker Engine. Por lo tanto, usar Docker Hub es la primera opción para que los desarrolladores compartan imágenes. Las imágenes del software de servicio común se pueden encontrar en Docker Centro

Los almacenes se dividen en almacenes públicos y almacenes privados. Los almacenes públicos generalmente se refieren a Docker Hub

Podemos buscar las imágenes que necesitamos usar en Dockers Hub

 El almacén espejo de uso común en China es Alibaba Cloud Container Mirror Warehouse

https://dev.aliyun.com/

4. Ejemplo de MySQL de instalación de Docker

(1) Descarga la imagen de MySQL

docker pull mysql:latest

(2) Ejecute la imagen de MySQL para obtener el contenedor y mapear el puerto

docker run -d -p 3306:3306 -e MYSQL_DATABASE=mydb -e MYSQL_ROOT_PASSWORD=123456 mysql:latest

-p 3306:3306  : asigne el puerto 3306 del servicio de contenedor al puerto 3306 del host, y el host externo puede acceder directamente al servicio MySQL a través de la IP del host: 3306

MYSQL_DATABASE=mydb : establezca el nombre de la base de datos utilizada por el servicio MySQL

MYSQL_ROOT_PASSWORD=123456 : establezca la contraseña del usuario root del servicio MySQL

Después de ejecutar la ventana acoplable, también puede seguir comandos como --restart always

1. --restart=always: cuando Docker se reinicia, el contenedor puede iniciarse automáticamente

docker run --restart detalles de valores de parámetros específicos

no: no reinicie el contenedor cuando salga;

en caso de falla: solo reinicie el contenedor si sale con un estado distinto de cero;

        –restart=on-failure:10 : Indica un máximo de 10 reinicios

siempre: reinicie el contenedor independientemente del estado de salida;
 

2. --privileged=true: monta el directorio del host y no informará problemas de permisos 

Si no se agrega --restart=always cuando Docker se está ejecutando y el contenedor Docker ya se está ejecutando, ejecute el siguiente comando 

# demo : 你的容器名称
docker update –-restart=always demo

(3) en el contenedor

docker exec -it 容器ID或者mysql名 /bin/bash

(4) Iniciar sesión en MySQL

mysql -u root -p

cambiar la contraseña

ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'

Autorización para agregar acceso de inicio de sesión de usuario remoto

CREATE USER 'admin'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%';

5. Ejemplo de instalación de Docker en SQL Server

Busque "Microsoft SQL Server" en docker hub

https://registry.hub.docker.com/_/microsoft-mssql-servidor

(1) Descargue la imagen de SQL Server

docker pull mcr.microsoft.com/mssql/server:2019-latest

  

(2) Ejecute la imagen de SQL Server para obtener el contenedor y mapear el puerto

docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=yourStrong(!)Password" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest

4. Imagen personalizada de Docker

Dockerfile es un archivo de texto que se utiliza para crear una imagen acoplable, y un Dockerfile consiste en instrucciones de comando línea por línea.

1. Estructura básica de Dockerfile

Información básica de la imagen

Información del mantenedor

Instrucciones de operación del espejo

Ejecutar instrucciones cuando se inicia el contenedor

2. instrucción Dockerfile

(1) DESDE

La directiva FROM se usa para especificar la imagen base de la imagen que se va a construir. Suele ser la primera instrucción en un Dockerfile.

El formato es: FROM <imagen> o FROM <imagen>:<etiqueta>

(2) MANTENEDOR

Información del mantenedor designado

El formato es: MANTENEDOR <nombre>

(3) ENV 

Especificar variables de entorno

ENV <clave> <valor>

(4) AGREGAR o COPIAR

Copie el archivo o directorio a la ruta especificada en el contenedor

AÑADIR <origen> <destino>

COPY <origen> <destino>

El comando ADD es similar a COPY (bajo los mismos requisitos, la recomendación oficial es usar COPY)

Ventajas de ADD: si <archivo de origen> es un archivo comprimido tar y el formato de compresión es gzip, bzip2 y xz, se copiará y descomprimirá automáticamente en <ruta de destino>

Desventaja de ADD: los archivos tar no se pueden copiar sin descompresión. Invalidará la memoria caché de compilación de imágenes, lo que puede ralentizar la compilación de imágenes. Se puede determinar si usarlo o no según si se requiere descompresión automática

(5) EXPONER

Describa el número de puerto expuesto por el contenedor del servidor Docker y asigne el puerto a través de -p al iniciar el contenedor.

El protocolo predeterminado es  tcp  , si es  el protocolo udp , debe agregar udp  más tarde   , como  80/udp

EXPOSE <puerto> [<puerto>/<protocolo>...]

EXPOSE 8080, lo que indica que el contenedor proporciona el puerto 8080 en tiempo de ejecución y se requiere la asignación de puertos al iniciar el contenedor

(6) CORRER

Ejecute comandos basados ​​en la imagen actual y cree una nueva capa de imagen, generalmente utilizada para actualizar o instalar software

EJECUTAR <comando>

(7) DMC

Especifique el comando a ejecutar al iniciar el contenedor. Cada Dockerfile solo puede tener un comando CMD. Si especifica varios comandos, solo se ejecutará el último.

Si se especifica un comando de ejecución al iniciar el contenedor, el comando especificado por CMD se sobrescribirá

El siguiente ejemplo de Dockerfile

Dockefile文件样例:
FROM XXX/jdk:8
MAINTAINER docker_user
ENV JAVA_ HОМE /usr/local/java
ADD apache -tomcat-8.0.32. tar.gz /usr/local/
RUN mv apache-tomcat-8.0.32 tomcat8
ÉXPOSE 8080
RÚN chmod u+x /usr/local/tomcat8/bin/* .sh
CMD /usr/ local/tomcat8/bin/catalina.sh start

1. Personaliza la imagen de JDK

FROM centos:latest
MAINTAINER admin
ADD jdk-8u121-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_121
ËNV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
CMD java -version

construir imagen

Use el Dockerfile en el directorio actual para crear una imagen y establecer la etiqueta

"." representa el directorio actual

El parámetro -t establece la etiqueta

docker build -t admin_jdk1.8.0_121 .

 2. Personaliza la imagen de Tomcat

FROM admin_jdk1.8.0_121
MAÌNTAINER admin
ADD apache-tomcat-8.5.24.tar.gz /usr/local/
ENV CATALINA_ HОME/usr/local/apache-tomcat-8.5.24
ENV PATH $PATH:$CATALINA_ HOME/Iib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-8.5.24/bin/catalina.sh run

3. Imagen MySQL personalizada

FROM centos:centos8
MAINTAINER admin
RUN yum install mysql-server mysqI -y
RUN /etc/init.d/mysqld start &&\
    mysql -e "grant all privileges on *.* to 'root'@'%' identified by '123456' WITH
GRANT OPTION ;" &&\
    mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by '123456'WITH GRANT OPTION ;" &&\
    mysql -uroot -p123456 -e "show databases;"
EXPOSE 3306
CMD /ûsr/bin/mysqld_safe

3. Publicar la imagen en el almacén de imágenes de Alibaba Cloud

Almacén de espejos en la nube de Alibaba

https://dev.aliyun.com/

Regístrese e inicie sesión en la cuenta de Aliyun; las cuentas de Taobao y Alipay pueden iniciar sesión en la consola o el centro de administración, buscar directamente [Servicio de duplicación de contenedores], seleccionar [Lista de fuerza], puede crear un [Almacén espejo], primero debe crear un [espacio de nombres]

 (1) Inicie sesión en el registro de Alibaba Cloud Docker

docker login [email protected] registry.cn-hangzhou.aliyuncs.com

El nombre de usuario para iniciar sesión es la cuenta de Aliyun, y la contraseña es la contraseña establecida cuando se activa el servicio

(2) Empuje la imagen al Registro

docker tag [lmageld] registry.cn-hangzhou.aliyuncs.com/123test/1234test:[镜像版本号心]
docker push registry.cn-hangzhou.aliyuncs.com/123test/1234test:[镜像版本号]

Reemplace los parámetros [lmageld] y [número de versión de la imagen] en el ejemplo de acuerdo con la información de la imagen real

acelerador de espejo

/etc/docker/daemon.json

Cinco, aplicación de implementación de Docker

1. Implementar un proyecto SpringBoot

(1) Empaquete el programa springboot en jar o war

(2) Cargue el paquete jar o war en un directorio de Linux, como /root/docker 

(3) Defina el archivo Dockerfile y cree una imagen de proyecto

2. Defina el Dockerfile del paquete jar

FROM admin_jdk1.8.0_121
MAINTAINER admin
ADD springboot-web-1.0.0.jar /opt
RUN chmod +X /opt/springboot-web-1.0.0.jar
CMD java -jar /opt/springboot-web-1.0.0.jar

3. Cree la imagen del programa del paquete jar

构建镜像: docker build -t springboot-web-jar .
运行容器: docker run -d 镜像ID

Después de ejecutar el contenedor, podemos ver el registro de operaciones.

docker logs -f --tail=100 容器名称

4. El programa del paquete jar depende del entorno del contenedor.

运行Redis容器: docker run -p 6379:6379 -d redis
运行MySQL 容器: docker run -p 3306:3306 -e MYSQL_DATABASE=mydb -e
MYSQL_ ROOT_ _PASSWORD=123456 -d mysql:latest

Después de que se inicie el contenedor MySQL, podemos acceder a la base de datos a través de la IP remota + puerto y contraseña de usuario. En este momento, si se cierra el contenedor MySQL, los datos se perderán.

Por lo tanto, después de modificar el contenedor, debe guardar

docker commit 容器id xxx(镜像名:tagxxx)

如:
docker commit 容器ID admin_mysql_new

Podemos entenderlo como una transacción comprometida en la base de datos, y una transacción no comprometida hará que los datos no se guarden correctamente 

Supongo que te gusta

Origin blog.csdn.net/MinggeQingchun/article/details/123411872
Recomendado
Clasificación