1. 首页 > Linux教程 > 正文

Linux教程FG584-基础设施即代码(IaC)实施案例

内容简介:本文详细介绍基础设施即代码(IaC)实施案例,包括IaC基础概念、工具选择、实施步骤和实战案例。参考Red Hat Enterprise Linux 10、Terraform、Ansible、CloudFormation官方文档等内容。

Part01-基础概念与理论知识

1.1 基础设施即代码基础概念

基础设施即代码(IaC)的基础概念:

  • 定义:使用代码来管理和配置基础设施,而不是手动操作
  • 核心原则:版本控制、自动化、一致性、可重复性
  • 类型:声明式(如Terraform、CloudFormation)和命令式(如Ansible、Chef)
  • 应用场景:云资源管理、服务器配置、网络配置、存储配置等

1.2 IaC工具介绍

常见的IaC工具:

Terraform

  • 类型:声明式
  • 特点:跨云平台、状态管理、模块化
  • 适用场景:云资源管理、多云环境
  • 文件格式:HCL(HashiCorp Configuration Language)

Ansible

  • 类型:命令式
  • 特点:无代理、易于使用、强大的自动化能力
  • 适用场景:服务器配置、应用部署、配置管理
  • 文件格式:YAML

CloudFormation

  • 类型:声明式
  • 特点:AWS原生、集成AWS服务
  • 适用场景:AWS云资源管理
  • 文件格式:JSON或YAML

Puppet

  • 类型:声明式
  • 特点:强大的配置管理、客户端-服务器架构
  • 适用场景:企业级配置管理
  • 文件格式:Puppet DSL

Chef

  • 类型:命令式
  • 特点:强大的配置管理、Ruby-based
  • 适用场景:企业级配置管理
  • 文件格式:Ruby

1.3 IaC优势

基础设施即代码的优势:

  • 一致性:确保环境配置的一致性,减少人为错误
  • 可重复性:可以快速复制环境,加速部署
  • 版本控制:基础设施配置可以像代码一样进行版本控制
  • 自动化:减少手动操作,提高效率
  • 可扩展性:易于扩展和管理大规模基础设施
  • 审计和合规:配置变更可追踪,便于审计
  • 成本优化:减少资源浪费,优化资源使用
  • 快速恢复:在故障时快速重建环境

Part02-生产环境规划与建议

2.1 工具选择

选择适合的IaC工具:

  • 考虑因素:云平台、团队技能、项目需求、复杂度
  • 单云环境:可以使用云厂商原生工具(如CloudFormation for AWS)
  • 多云环境:建议使用Terraform等跨云工具
  • 配置管理:建议使用Ansible等配置管理工具
  • 混合环境:结合使用多种工具

2.2 IaC策略

制定IaC策略:

  • 模块化设计:将基础设施代码模块化,提高可重用性
  • 环境分离:为开发、测试、生产环境创建独立的配置
  • 变量管理:使用变量管理不同环境的配置
  • 状态管理:合理管理基础设施状态
  • 自动化测试:对基础设施代码进行测试

2.3 安全考虑

IaC安全考虑:

  • 密钥管理:安全管理API密钥和密码
  • 权限控制:实施最小权限原则
  • 安全扫描:扫描基础设施代码中的安全漏洞
  • 合规性:确保基础设施配置符合合规要求
  • 审计日志:记录基础设施变更

2.4 版本控制from PG视频:www.itpux.com

h3>

版本控制策略:

  • 代码仓库:使用Git等版本控制系统
  • 分支策略:使用功能分支、发布分支等策略
  • 代码审查:实施代码审查流程
  • 变更管理:建立变更管理流程
  • 回滚策略:制定回滚策略,应对失败的部署

Part03-生产环境项目实施方案

3.1 Terraform实施

Terraform实施:

3.1.1 Terraform基础配置

# 安装Terraform
$ sudo dnf install -y unzip
$ wget https://releases.hashicorp.com/terraform/1.3.7/terraform_1.3.7_linux_amd64.zip
$ unzip terraform_1.3.7_linux_amd64.zip
$ sudo mv terraform /usr/local/bin/

# 验证安装
$ terraform –version
Terraform v1.3.7

# 初始化Terraform项目
$ mkdir terraform-project
$ cd terraform-project
$ terraform init

# 创建main.tf文件
$ cat > main.tf << 'EOF' provider "aws" { region = "us-west-2" } resource "aws_instance" "web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" tags = { Name = "Web Server" } } resource "aws_security_group" "web" { name = "web-sg" description = "Allow HTTP traffic" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } EOF # 计划变更 $ terraform plan # 应用变更 $ terraform apply # 查看状态 $ terraform show # 销毁资源 $ terraform destroy

3.1.2 Terraform模块化

# 创建模块目录
$ mkdir -p modules/vpc
$ mkdir -p modules/ec2

# 创建VPC模块
$ cat > modules/vpc/main.tf << 'EOF' resource "aws_vpc" "main" { cidr_block = var.cidr_block tags = { Name = var.name } } resource "aws_subnet" "public" { vpc_id = aws_vpc.main.id cidr_block = var.public_subnet_cidr tags = { Name = "${var.name}-public" } } resource "aws_internet_gateway" "gw" { vpc_id = aws_vpc.main.id tags = { Name = "${var.name}-igw" } } resource "aws_route_table" "public" { vpc_id = aws_vpc.main.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.gw.id } tags = { Name = "${var.name}-public-rt" } } resource "aws_route_table_association" "public" { subnet_id = aws_subnet.public.id route_table_id = aws_route_table.public.id } EOF # 创建VPC模块变量 $ cat > modules/vpc/variables.tf << 'EOF' variable "cidr_block" { description = "VPC CIDR block" type = string } variable "name" { description = "VPC name" type = string } variable "public_subnet_cidr" { description = "Public subnet CIDR" type = string } EOF # 创建EC2模块 $ cat > modules/ec2/main.tf << 'EOF' resource "aws_instance" "web" { ami = var.ami instance_type = var.instance_type subnet_id = var.subnet_id vpc_security_group_ids = [var.security_group_id] tags = { Name = var.name } } EOF # 创建EC2模块变量 $ cat > modules/ec2/variables.tf << 'EOF' variable "ami" { description = "AMI ID" type = string } variable "instance_type" { description = "Instance type" type = string } variable "subnet_id" { description = "Subnet ID" type = string } variable "security_group_id" { description = "Security group ID" type = string } variable "name" { description = "Instance name" type = string } EOF # 使用模块 $ cat > main.tf << 'EOF' provider "aws" { region = "us-west-2" } module "vpc" { source = "./modules/vpc" cidr_block = "10.0.0.0/16" name = "my-vpc" public_subnet_cidr = "10.0.1.0/24" } resource "aws_security_group" "web" { name = "web-sg" description = "Allow HTTP traffic" vpc_id = module.vpc.vpc_id ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } module "ec2" { source = "./modules/ec2" ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" subnet_id = module.vpc.public_subnet_id security_group_id = aws_security_group.web.id name = "web-server" } EOF # 初始化并应用 $ terraform init $ terraform apply

3.2 Ansible实施

Ansible实施:

3.2.1 Ansible基础配置

# 安装Ansible
$ sudo dnf install -y ansible

# 验证安装
$ ansible –version
ansible [core 2.13.3]

# 创建Ansible配置
$ cat > ansible.cfg << 'EOF' [defaults] inventory = inventory.ini remote_user = ansible private_key_file = ~/.ssh/id_rsa EOF # 创建inventory.ini $ cat > inventory.ini << 'EOF' [web] web1 ansible_host=192.168.1.101 web更多学习教程公众号风哥教程itpux_com2 ansible_host=192.168.1.102 [db] db1 ansible_host=192.168.1.201 EOF # 创建Playbook $ cat > web-server.yml << 'EOF' --- - hosts: web tasks: - name: Install Nginx dnf: name: nginx state: present - name: Start Nginx service: name: nginx state: started enabled: yes - name: Copy index.html copy: src: files/index.html dest: /usr/share/nginx/html/ - name: Configure firewall firewalld: service: http state: enabled permanent: yes immediate: yes EOF # 创建文件目录和index.html $ mkdir -p files $ echo "Hello from Ansible" > files/index.html

# 运行Playbook
$ ansible-playbook web-server.学习交流加群风哥微信: itpux-comyml

# 检查结果
$ ansible web -m command -a “curl http://localhost”

3.2.2 Ansible Roles

# 创建Roles目录结构
$ mkdir -p roles/webserver/tasks
$ mkdir -p roles/webserver/templates
$ mkdir -p roles/webserver/files

# 创建tasks/main.yml
$ cat > roles/webserver/tasks/main.yml << 'EOF' --- - name: Install Nginx dnf: name: nginx state: present - name: Start Nginx service: name: nginx state: started enabled: yes - name: Copy index.html copy: src: index.html dest: /usr/share/nginx/html/ - name: Copy Nginx config template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: - restart nginx - name: Configure firewall firewalld: service: http state: enabled permanent: yes immediate: yes EOF # 创建templates/nginx.conf.j2 $ cat > roles/webserver/templates/nginx.conf.j2 << 'EOF' user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; server { listen 80; server_name {{ server_name }}; root /usr/share/nginx/html; location / { } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } } EOF # 创建files/index.html $ echo "Hello from Ansible Role" > roles/webserver/files/index.html

# 创建handlers/main.yml
$ cat > roles/webserver/handlers/main.yml << 'EOF' --- - name: restart nginx service: name: nginx state: restarted EOF # 创建Playbook使用Role $ cat > site.yml << 'EOF' --- - hosts: web roles: - role: webserver vars: server_name: fgedu.net.cn EOF # 运行Playbook $ ansible-playbook site.yml

3.3 CloudFormation实施

CloudFormation实施:

3.3.1 CloudFormation模板

# 创建CloudFormation模板
$ cat > cloudformation.yml << 'EOF' AWSTemplateFormatVersion: '2010-09-09' Description: 'Web Server Stack' Parameters: InstanceType: Description: EC2 instance type Type: String Default: t2.micro AllowedValues: - t2.micro - t2.small - t2.medium KeyName: Description: EC2 Key Pair Type: AWS::EC2::KeyPair::KeyName Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 Tags: - Key: Name Value: WebVPC PublicSubnet: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: true Tags: - Key: Name Value: PublicSubnet InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: WebIGW AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: PublicRT PublicRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway SubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTP traffic VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: WebSG EC2Instance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType KeyName: !Ref KeyName ImageId: ami-0c55b159cbfafe1f0 SubnetId: !Ref PublicSubnet SecurityGroupIds: - !Ref SecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash -xe yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "Hello from CloudFormation" > /var/www/html/index.html
Tags:
– Key: Name
Value: WebServer

Outputs:
PublicIP:
Description: Public IP address of the EC2 instance
Value: !GetAtt EC2Instance.PublicIp
PublicDNS:
Description: Public DNS name of the EC2 instance
Value: !GetAtt EC2Instance.PublicDnsName
EOF

# 部署CloudFormation堆栈
$ aws cloudformation create-stack –stack-name web-stack –template-body file://cloudformation.yml –parameters ParameterKey=KeyName,ParameterValue=my-key-pair

# 查看堆栈状态
$ aws cloudformation describe-stacks –stack-name web-stack

# 更新堆栈
$ aws cloudformation update-stack –stack-name web-stack –template-body file://cloudformation.yml –parameters ParameterKey=InstanceType,ParameterValue=t2.small ParameterKey=KeyName,ParameterValue=my-key-pair

# 删除堆栈
$ aws cloudformation delete-stack –stack-name web-stack

3.4 IaC流水线

IaC流水线实施:

3.4.1 GitLab CI/CD流水线

# 创建.gitlab-ci.yml
$ cat > .gitlab-ci.yml << 'EOF' stages: - validate - plan - apply - test - destroy validate: stage: validate script: - terraform validate plan: stage: plan script: - terraform plan -out=tfplan artifacts: paths: - tfplan apply: stage: apply script: - terraform apply -auto-approve tfplan only: - master test: stage: test script: - ansible-playbook test.yml destroy: stage: destroy script: - terraform destroy -auto-approve when: manual only: - master EOF # 创建test.yml $ cat > test.yml << 'EOF' --- - hosts: all tasks: - name: Test HTTP access uri: url: http://{{ ansible_host }} status_code: 200 EOF

Part04-生产案例与实战讲解

4.1 Terraform实战案例

Terraform实战案例:

4.1.1 多环境部署

# 案例背景:使用Terraform管理多环境部署

# 目录结构
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ └── variables.tf
│ ├── test/
│ │ ├── main.tf
│ │ └── variables.tf
│ └── prod/
│ ├── main.tf
│ └── variables.tf
├── modules/
│ ├── vpc/
│ ├── ec2/
│ └── rds/
└── terraform.tfvars

# 环境配置
$ cat > environments/dev/variables.tf << 'EOF' variable "environment" { default = "dev" } variable "instance_type" { default = "t2.micro" } variable "instance_count" { default = 1 } EOF $ cat > environments/prod/variables.tf << 'EOF' variable "environment" { default = "prod" } variable "instance_type" { default = "t2.large" } variable "instance_count" { default = 3 } EOF # 部署开发环境 $ cd environments/dev $ terraform init $ terraform apply # 部署生产环境 $ cd ../prod $ terraform init $ terraform apply # 成果 - 实现了环境隔离 - 统一的基础设施代码 - 快速部署和管理多环境

4.2 Ansible实战案例

Ansible实战案例:

4.2.1 配置管理

# 案例背景:使用Ansible管理服务器配置

# 目录结构
├── ansible.cfg
├── inventory.ini
├── playbooks/
│ ├── common.yml
│ ├── webserver.yml
│ └── database.yml
└── roles/
├── common/
├── webserver/
└── database/

# 运行Playbook
$ ansible-playbook playbooks/common.yml
$ ansible-playbook playbooks/webserver.yml
$ ansible-playbook playbooks/database.yml

# 成果
– 统一的配置管理
– 自动化部署和配置
– 减少人为错误
– 提高管理效率

4.3 CloudFormation实战案例

CloudFormation实战案例:

4.3.1 高可用架构部署

# 案例背景:使用CloudFormation部署高可用架构

# 模板内容
$ cat > high-availability.yml << 'EOF' AWSTemplateFormatVersion: '2010-09-09' Description: 'High Availability Web Application' Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.1.0/24 AvailabilityZone: !Select [0, !GetAZs ''] PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: 10.0.2.0/24 AvailabilityZone: !Select [1, !GetAZs ''] InternetGateway: Type: AWS::EC2::InternetGateway AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PublicRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway Subnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable Subnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTP and SSH VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: 0.0.0.0/0 LaunchConfiguration: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: ami-0c55b159cbfafe1f0 InstanceType: t2.micro SecurityGroups: [!Ref SecurityGroup] UserData: Fn::Base64: !Sub | #!/bin/bash -xe yum update -y yum install -y httpd systemctl start httpd systemctl enable httpd echo "Hello from HA Stack" > /var/www/html/index.html

AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
LaunchConfigurationName: !Ref LaunchConfiguration
MinSize: 2
MaxSize: 4
DesiredCapacity: 2
VPCZoneIdentifier: [!Ref PublicSubnet1, !Ref PublicSubnet2]

LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: WebLoadBalancer
Subnets: [!Ref PublicSubnet1, !Ref PublicSubnet2]
SecurityGroups: [!Ref SecurityGroup]

TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: WebTargetGroup
Port: 80
Protocol: HTTP
VpcId: !Ref VPC

Listener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Port: 80
Protocol: HTTP
DefaultActions:
– Type: forward
TargetGroupArn: !Ref TargetGroup

AutoScalingGroupAttachment:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
TargetGroupARNs: [!Ref TargetGroup]
EOF

# 部署堆栈
$ aws cloudformation create-stack –stack-name ha-stack –template-body file://high-availability.yml

# 成果
– 高可用架构
– 自动扩展
– 负载均衡
– 多可用区部署

4.4 多云环境IaC案例

多云环境IaC案例:

4.4.1 跨云部署

# 案例背景:使用Terraform部署跨云环境

# 配置多个云提供商
$ cat > main.tf << 'EOF' # AWS Provider provider "aws" { region = "us-west-2" } # Azure Provider provider "azurerm" { features {} subscription_id = var.azure_subscription_id tenant_id = var.azure_tenant_id client_id = var.azure_client_id client_secret = var.azure_client_secret } # GCP Provider provider "google" { project = var.更多视频教程www.fgedu.net.cngcp_project region = "us-central1" } # AWS Resources resource "aws_instance" "aws_web" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t2.micro" tags = { Name = "AWS Web Server" } } # Azure Resources resource "azurerm_resource_group" "rg" { name = "example-resources" location = "West Europe" } resource "azurerm_virtual_machine" "azure_web" { name = "azure-web" location = azurerm_resource_group.rg.location resource_group_name = azurerm_resource_group.rg.name network_interface_ids = [azurerm_network_interface.ni.id] vm_size = "Standard_B1s" storage_image_reference { publisher = "Canonical" offer = "UbuntuServer" sku = "18.04-LTS" version = "latest" } storage_os_disk { name = "osdisk" caching = "ReadWrite" create_option = "FromImage" managed_disk_type = "Standard_LRS" } os_profile { computer_name = "azure-web" admin_username = "adminuser" admin_password = "Password1234!" } os_profile_linux_config { disable_password_authentication = false } } # GCP Resources resource "google_compute_instance" "gcp_web" { name = "gcp-web" machine_type = "e2-micro" zone = "us-central1-a" boot_disk { initialize_params { image = "debian-cloud/debian-10" } } network_interface { network = "default" access_config {} } } EOF # 部署跨云环境 $ terraform init $ terraform apply # 成果 - 跨云资源管理 - 统一的基础设施代码 - 简化多云环境管理

Part05-风哥经验总结与分享

5.1 最佳实践

基础设施即代码的最佳实践:

  • 模块化设计:将基础设施代码模块化,提高可重用性
  • 环境分离:为不同环境创建独立的配置
  • 变量管理:使用变量和参数管理配置
  • 状态管理:合理管理基础设施状态
  • 版本控制:使用Git等版本控制系统
  • 代码审查:实施代码审查流程
  • 自动化测试:对基础设施代码进行测试
  • 安全扫描:扫描基础设施代码中的安全漏洞
  • 文档:为基础设施代码编写文档
  • 持续集成:实施CI/CD流水线

5.2 故障排查

基础设施即代码的故障排查:

  • 状态问题:检查Terraform状态文件
  • 权限问题:检查云平台权限
  • 网络问题:检查网络配置和安全组
  • 资源冲突:检查资源名称和ID
  • 依赖问题:检查资源依赖关系
  • 版本问题:检查工具版本兼容性
  • 配置错误:检查配置文件语法和参数
  • 日志分析:分析工具和云平台日志

5.3 性能优化

基础设施即代码的性能优化:

  • 并行执行:使用并行执行加速部署
  • 模块化:合理组织代码结构
  • 状态管理:使用远程状态存储
  • 缓存:使用缓存加速部署
  • 资源优化:合理配置资源参数
  • 批量操作:使用批量操作减少API调用
  • 错误处理:实现错误处理和重试机制
  • 监控:监控部署过程和资源状态

风哥提示:

基础设施即代码是现代DevOps实践的核心,通过使用代码管理基础设施,可以提高部署效率,确保环境一致性,减少人为错误。选择适合的工具,制定合理的策略,实施最佳实践,是成功实施IaC的关键。from Linux:www.itpux.com

持续学习:基础设施即代码技术发展迅速,建议定期更新知识,关注行业趋势,不断提升自己的技能水平。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息