使用资源编排 ROS 轻松部署单点网站——以 WordPress 为例

news/2024/11/18 19:45:43/文章来源:https://www.cnblogs.com/alicloudros/p/18292389

介绍

WordPress是一款免费开源的网站内容管理系统(CMS),它可以帮助用户简单快捷地创建和管理自己的网站,包括博客、新闻网站、电子商务网站、社交网络等等。WordPress 有丰富的主题和插件库,使得用户可以轻松地为网站定制外观和功能。WordPress 的易用性和可扩展性使其成为世界上最受欢迎的网站建设工具之一。

资源编排服务(Resource Orchestration Service, ROS)是阿里云提供基于基础设施即代码(Infrastructure as Code, IaC) 理念的自动化部署服务,我们可以通过定义一个 JSON/YAML/Terraform 模板,轻松部署一套云上单点网站环境。比如部署一套 WordPress 环境,包括创建 VPC、ECS 等云资源,在 ECS 实例中安装 PHP、MySQL 和 WordPress 等。

部署步骤

  1. 登录ROS 控制台-WordPress 部署页面
  2. 配置模板参数:选择 ECS 实例的可用区、实例类型、系统盘类型、实例密码、数据库用户密码

1.png

  1. 点击【下一步】,然后【创建】。部署完成后,点击资源栈的输出,即可看到 WordPress 服务的地址。点击链接即可体验 WordPress 的功能。

2.jpg

3.jpg

部署原理

我们可以看到通过 ROS 可以非常快捷地部署阿里云上的各种云资源(比如 VPC、VSwitch、ECS 实例等)和应用程序(比如 WordPress)。如果想了解是如何做到的,那么可以阅读此章节。

  1. 编写 ROS 模板。在如下模板中定义了:
  • Resources:定义了 VPC、VSwitch、ECS 实例、安全组、安全组规则以及安装 WordPress 的命令执行。
  • Parameters:定义了常用的参数,比如可用区、ECS 实例类型类型。
  • Outputs:定义了自定义输出,比如 WordPress 服务的地址。
ROSTemplateFormatVersion: "2015-09-01"
Description:en: Manually build a WordPress website on a CentOS 7 ECS instance.zh-cn: 在ECS实例(CentOS 7)上搭建WordPress。
Conditions:CreateInstance:Fn::Equals:- Ref: InstanceSource- CreateNew
Parameters:InstanceSource:Type: StringDefault: CreateNewLabel:zh-cn: 实例来源en: Instance SourceAllowedValues:- CreateNew- UseExistedAssociationPropertyMetadata:ValueLabelMapping:CreateNew:zh-cn: 创建新实例en: Create New InstanceUseExisted:zh-cn: 选择已有实例en: Select Existed InstanceInstanceId:Type: StringLabel:en: Existing ECS Instancezh-cn: 已创建ECS实例Description:en: Select an ECS instance with the CentOS 7.9 64-bit operating system.zh-cn: 选择已存在操作系统为CentOS 7.9 64位的ECS实例。AssociationProperty: ALIYUN::ECS::Instance::InstanceIdAssociationPropertyMetadata:Visible:Condition:Fn::Equals:- ${InstanceSource}- UseExistedDefault: NullZoneId:Type: StringLabel:en: VSwitch Availability Zonezh-cn: 可用区IDDescription:en: Availability Zone ID,<br><b>note: <font color='blue'>Before selecting, please confirm that the Availability Zone supports the specification of creating ECS resources.</font></b>zh-cn: 可用区ID。<br><b>注: <font color='blue'>选择可用区前请确认该可用区是否支持创建ECS资源的规格。</font></b>Required: trueAssociationProperty: ALIYUN::ECS::Instance:ZoneIdAssociationPropertyMetadata:ZoneId: ZoneIdVisible:Condition:Fn::Equals:- ${InstanceSource}- CreateNewDefault: NullInstanceType:Type: StringLabel:en: Instance Typezh-cn: 实例类型Description:en: "See detail: <a href='https://www.alibabacloud.com/help/en/doc-detail/25378.html' target='_blank'><b><font color='blue'>Instance Specification Family</font></a></b>"zh-cn: 规格详见:<a href='https://help.aliyun.com/document_detail/25378.html' target='_blank'><b><font color='blue'>实例规格族</font></a></b>Required: trueAssociationProperty: ALIYUN::ECS::Instance::InstanceTypeAssociationPropertyMetadata:DefaultValueStrategy: recentZoneId: ZoneIdVisible:Condition:Fn::Equals:- ${InstanceSource}- CreateNewDefault: ecs.c5.largeSystemDiskCategory:Type: StringLabel:en: System Disk Typezh-cn: 系统盘类型Required: trueAssociationProperty: ALIYUN::ECS::Disk::SystemDiskCategoryAssociationPropertyMetadata:AutoSelectFirst: trueAutoChangeType: falseLocaleKey: DiskCategoryInstanceType: ${InstanceType}ZoneId: ZoneIdVisible:Condition:Fn::Equals:- ${InstanceSource}- CreateNewDefault: cloud_essdInstancePassword:Type: StringLabel:en: Instance Passwordzh-cn: 实例密码Description:en: Server login password, Length 8-30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in).zh-cn: 服务器登录密码,长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。ConstraintDescription:en: Length 8-30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in).zh-cn: 长度8-30,必须包含三项(大写字母、小写字母、数字、 ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ 中的特殊符号)。AllowedPattern: '[0-9A-Za-z\_\-\&:;''<>,=%`~!@#\(\)\$\^\*\+\|\{\}\[\]\.\?\/]+$'AssociationPropertyMetadata:Required: trueVisible:Condition:Fn::Equals:- ${InstanceSource}- CreateNewMinLength: 8MaxLength: 30NoEcho: trueDefault: NullDbPassword:Type: StringLabel:en: DB User Passwordzh-cn: 数据库用户密码Description:en: |-The password must be 8 to 32 characters in length. <br>It must contain the following character types: uppercase letters, lowercase letters, digits, and special characters. <br> Special characters include <span style="background:#E7E9EB;"><b>!@#$%^&*()_+-=</b></span>.<br><b>If you repeatedly provision in this tutorial on the same ECS instance, make sure that the MySQL database password is exactly the same as the password set when the template was executed for the first time. Otherwise, the result of provisioning is unavailable.</b>zh-cn: |-长度为8~32位,需包含大写字母、小写字母、特殊字符和数字,允许的特殊字符包括<span style="background:#E7E9EB;"><b>!@#$%^&*()_+-=</b></span>。<br> <b>如果您在同一台ECS实例上重复执行本教程的一键配置模板,请确保MySQL数据库密码和第一次执行模板时设置的密码完全一致。否则一键配置结果不可用。</b>ConstraintDescription:en: |-The password must be 8 to 32 characters in length. <br>It must contain the following character types: uppercase letters, lowercase letters, digits, and special characters. <br> Special characters include <span style="background:#E7E9EB;"><b>!@#$%^&*()_+-=</b></span>.<br><b>If you repeatedly provision in this tutorial on the same ECS instance, make sure that the MySQL database password is exactly the same as the password set when the template was executed for the first time. Otherwise, the result of provisioning is unavailable.</b>zh-cn: 长度为8~32位,需包含四项大写字母、小写字母、特殊字符和数字,允许的特殊字符包括<span style="background:#E7E9EB;"><b>!@#$%^&*()_+-=</b></span>。AllowedPattern: ^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])((?=.*[!@#\$%\^&\*\(\)\-\+])|(?=.*[_\.,:;\-\?]))[a-zA-Z0-9!@#\$%\^&\*\(\)\-\+_\.,:;\-\?]{8,32}$Required: trueNoEcho: true
Resources:Vpc:Type: ALIYUN::ECS::VPCCondition: CreateInstanceProperties:CidrBlock: 192.168.0.0/16VSwitch:Type: ALIYUN::ECS::VSwitchCondition: CreateInstanceProperties:ZoneId:Ref: ZoneIdVpcId:Ref: VpcCidrBlock: 192.168.0.0/24SecurityGroup:Type: ALIYUN::ECS::SecurityGroupCondition: CreateInstanceProperties:VpcId:Ref: VpcSecurityGroupIngress_22:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Fn::Jq:- First- .[0].SecurityGroupIds[0]- Fn::GetAtt:- DS_Instances- InstancesSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 22/22SecurityGroupIngress_80:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Fn::Jq:- First- .[0].SecurityGroupIds[0]- Fn::GetAtt:- DS_Instances- InstancesSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 80/80SecurityGroupIngress_443:Type: ALIYUN::ECS::SecurityGroupIngressProperties:SecurityGroupId:Fn::Jq:- First- .[0].SecurityGroupIds[0]- Fn::GetAtt:- DS_Instances- InstancesSourceCidrIp: 0.0.0.0/0IpProtocol: tcpNicType: intranetPortRange: 443/443WaitConditionHandle:Type: ALIYUN::ROS::WaitConditionHandleProperties: {}RosWaitCondition:Type: ALIYUN::ROS::WaitConditionProperties:Count: 1Handle:Ref: WaitConditionHandleTimeout: 7200DS_Instances:Type: DATASOURCE::ECS::InstancesProperties:InstanceIds:Fn::If:- CreateInstance- Fn::GetAtt:- InstanceGroup- InstanceIds- - Ref: InstanceIdInstanceGroup:Type: ALIYUN::ECS::InstanceGroupCondition: CreateInstanceProperties:VpcId:Ref: VpcVSwitchId:Ref: VSwitchSecurityGroupId:Ref: SecurityGroupImageId: centos_7_8InstanceType:Ref: InstanceTypeSystemDiskCategory:Ref: SystemDiskCategoryPassword:Ref: InstancePasswordIoOptimized: optimizedMaxAmount: 1InstallWordpress:Type: ALIYUN::ECS::RunCommandProperties:InstanceIds:Fn::If:- CreateInstance- Fn::GetAtt:- InstanceGroup- InstanceIds- - Ref: InstanceIdType: RunShellScriptSync: trueTimeout: 7200CommandContent:Fn::Sub:- |-#!/bin/bashif [ ! -f .ros.provision ]; thenecho "Name: 手动搭建WordPress(CentOS 7)" > .ros.provisionfiname=$(grep "^Name:" .ros.provision | awk -F':' '{print $2}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')if [[ "$name" != "手动搭建WordPress(CentOS 7)" ]]; thenecho "当前实例已使用过\"$name\"教程的一键配置,不能再使用本教程的一键配置"${WaitConditionHandle.CurlCli} --data-binary "{\"status\": \"FAILURE\", \"reason\": \"The current instance has already applied the configuration of the \\\"$name\\\" tutorial, and the configuration of this tutorial can no longer be applied.\"}"exit 0fiecho "#########################"echo "# Check Network"echo "#########################"ping -c 2 -W 2 aliyun.com > /dev/nullif [[ $? -ne 0 ]]; thenecho "当前实例无法访问公网"${WaitConditionHandle.CurlCli} --data-binary "{\"status\": \"FAILURE\", \"reason\": \"The current instance cannot access the public network.\"}"exit 0fiif ! grep -q "^Step1: Prepare Environment$" .ros.provision; thenecho "#########################"echo "# Prepare Environment"echo "#########################"systemctl status firewalldsystemctl stop firewalldecho "Step1: Prepare Environment" >> .ros.provisionelseecho "#########################"echo "# Environment has been ready"echo "#########################"fiif ! grep -q "^Step2: Install Nginx$" .ros.provision; thenecho "#########################"echo "# Install Nginx"echo "#########################"yum -y install nginxnginx -vecho "Step2: Install Nginx" >> .ros.provisionelseecho "#########################"echo "# Nginx has been installed"echo "#########################"fiif ! grep -q "^Step3: Install MySQL$" .ros.provision; thenecho "#########################"echo "# Install MySQL"echo "#########################"rpm -Uvh  https://dev.mysql.com/get/mysql57-community-release-el7-9.noarch.rpmyum -y install mysql-community-server --nogpgcheckmysql -Vsystemctl start mysqldsystemctl enable mysqldsystemctl daemon-reloadecho "Step3: Install MySQL" >> .ros.provisionelseecho "#########################"echo "# MySQL has been installed"echo "#########################"fiif ! grep -q "^Step4: Install PHP$" .ros.provision; thenecho "#########################"echo "# Install PHP"echo "#########################"yum install -y \https://mirrors.aliyun.com/ius/ius-release-el7.rpm \https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpmyum -y install php-devel php php-cli php-common php-gd php-ldap php-mbstring php-mcrypt php-pdo php-fpm php-opcache php-pecl-redis php-pecl-mongodb php-mysqlndphp -vecho "Step4: Install PHP" >> .ros.provisionelseecho "#########################"echo "# PHP has been installed"echo "#########################"fiif ! grep -q "^Step4: Config Nginx$" .ros.provision; thenecho "#########################"echo "# Config Nginx"echo "#########################"cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bakcat > /etc/nginx/nginx.conf << \EOF# For more information on configuration, see:#   * Official English Documentation: http://nginx.org/en/docs/#   * Official Russian Documentation: http://nginx.org/ru/docs/user nginx;worker_processes auto;error_log /var/log/nginx/error.log;pid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.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 4096;include             /etc/nginx/mime.types;default_type        application/octet-stream;# Load modular configuration files from the /etc/nginx/conf.d directory.# See http://nginx.org/en/docs/ngx_core_module.html#include# for more information.include /etc/nginx/conf.d/*.conf;server {listen       80;listen       [::]:80;server_name  _;root         /usr/share/nginx/html/wordpress;# Load configuration files for the default server block.include /etc/nginx/default.d/*.conf;location / {index index.php index.html index.htm;}location ~ .php$ {root /usr/share/nginx/html/wordpress;    # 将/usr/share/nginx/html替换为您的网站根目录,本文使用/usr/share/nginx/html作为网站根目录。fastcgi_pass 127.0.0.1:9000;   # Nginx通过本机的9000端口将PHP请求转发给PHP-FPM进行处理。fastcgi_index index.php;fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;include fastcgi_params;   # Nginx调用fastcgi接口处理PHP请求。}error_page 404 /404.html;location = /404.html {}error_page 500 502 503 504 /50x.html;location = /50x.html {}}# Settings for a TLS enabled server.##    server {#        listen       443 ssl http2;#        listen       [::]:443 ssl http2;#        server_name  _;#        root         /usr/share/nginx/html;##        ssl_certificate "/etc/pki/nginx/server.crt";#        ssl_certificate_key "/etc/pki/nginx/private/server.key";#        ssl_session_cache shared:SSL:1m;#        ssl_session_timeout  10m;#        ssl_ciphers HIGH:!aNULL:!MD5;#        ssl_prefer_server_ciphers on;##        # Load configuration files for the default server block.#        include /etc/nginx/default.d/*.conf;##        error_page 404 /404.html;#            location = /40x.html {#        }##        error_page 500 502 503 504 /50x.html;#            location = /50x.html {#        }#    }}EOFsystemctl start nginxsystemctl enable nginxecho "Step4: Config Nginx" >> .ros.provisionelseecho "#########################"echo "# Nginx has been configured"echo "#########################"fiif ! grep -q "^Step6: Config MySQL$" .ros.provision; thenecho "#########################"echo "# Config MySQL"echo "#########################"export MYSQL_PWD=`grep "temporary password" /var/log/mysqld.log | awk '{print $NF}'`mysqladmin -uroot password '${DbPassword}'export MYSQL_PWD='${DbPassword}'mysql -uroot -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '${DbPassword}'"echo CREATE DATABASE wordpress\; >> /tmp/setup.mysqlecho CREATE user "user"@"localhost" identified by '"${DbPassword}"'\; >> /tmp/setup.mysqlecho GRANT ALL privileges ON wordpress.* TO "user"@"localhost" IDENTIFIED BY '"${DbPassword}"'\; >> /tmp/setup.mysqlecho FLUSH privileges\;>> /tmp/setup.mysqlchmod 400 /tmp/setup.mysqlmysql -u root --password='${DbPassword}' < /tmp/setup.mysql          echo "Step6: Config MySQL" >> .ros.provisionelseecho "#########################"echo "# MySQL has been configured"echo "#########################"fiif ! grep -q "^Step7: Config PHP$" .ros.provision; thenecho "#########################"echo "# Config PHP"echo "#########################"echo "<?php phpinfo(); ?>" > /usr/share/nginx/html/phpinfo.phpsystemctl start php-fpmsystemctl enable php-fpmecho "Step7: Config PHP" >> .ros.provisionelseecho "#########################"echo "# PHP has been configured"echo "#########################"fiif ! grep -q "^Step8: Install wordpress$" .ros.provision; thenecho "#########################"echo "# Install wordpress"echo "#########################"yum -y install wordpressecho "Step8: Install wordpress" >> .ros.provisionelseecho "#########################"echo "# wordpress has been installed"echo "#########################"fiif ! grep -q "^Step9: Config wordpress$" .ros.provision; thenecho "#########################"echo "# Config wordpress"echo "#########################"mv /usr/share/wordpress /usr/share/nginx/html/wordpresscd /usr/share/nginx/html/wordpressln -snf /etc/wordpress/wp-config.php wp-config.phpsed -i "s/database_name_here/wordpress/" wp-config.phpsed -i "s/username_here/user/" wp-config.phpsed -i "s/password_here/${DbPassword}/" wp-config.phpecho "Step9: Config wordpress" >> .ros.provisionelseecho "#########################"echo "# wordpress has been configured"echo "#########################"fisystemctl restart nginx${WaitConditionHandle.CurlCli} --data-binary '{"status": "SUCCESS"}'- IP:Fn::Jq:- First- if .[0].PublicIpAddress != [] then .[0].PublicIpAddress[0] else .[0].EipAddress.IpAddress end- Fn::GetAtt:- DS_Instances- InstancesDependsOn:- SecurityGroupIngress_22- SecurityGroupIngress_443- SecurityGroupIngress_80
Outputs:WordPressUrl:Description:zh-cn: WordPress 地址en: WordPress AddressValue:Fn::Sub:- http://${IP}- IP:Fn::Jq:- First- if .[0].PublicIpAddress != [] then .[0].PublicIpAddress[0] else .[0].EipAddress.IpAddress end- Fn::GetAtt:- DS_Instances- Instances
Metadata:ALIYUN::ROS::Interface:ParameterGroups:- Parameters:- InstanceSource- InstanceId- ZoneId- InstanceType- SystemDiskCategory- InstancePassword- DbPasswordLabel:default: ECSTemplateTags:- acs:example:web:搭建WordPress(CentOS 7)
  1. 在 ROS 控制台中使用此模板创建资源栈。ROS 会自动解析出模板中资源的依赖关系,按照资源依赖顺序创建云资源。如果资源间没有依赖,则会并发创建,从而提升部署效率。ROS 会把这次创建的所有资源存放到一个“资源栈”中,后续可以方便地管理这组资源集合。比如:
  • 将新模板应用到这个“资源栈”中,从而更新里面的资源。
  • 删除这个“资源栈”,从而把所有的资源删掉。

总结

基于 IaC 的理念,通过定义一个模板,使用 ROS 进行自动化部署,可以非常高效快捷地部署任意云资源和应用(比如 WordPress 服务)。相比于手动部署或者通过 API、SDK 的部署方式,有着高效、稳定等诸多优势,也是服务上云的最佳实践。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/741238.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Java SE] Java-文件系统-常用文件路径的获取方法

1 获取相对路径 /*** 获取相对路径 【推荐】* 使用Java提供的Path类和Paths类来获取相对路径。* 例如,假设有两个路径a和b,我们可以使用Path类的relativize()方法来获取相对路径,该方法返回一个相对路径的Path对象。*/ @Test public void getRelativePathTest1(){Path pathA…

CH582 CH592 CH573 BLE central主机获取handle值

GATT_DiscCharsByUUID和GATT_ReadUsingCharUUID 差异

[深入理解Java虚拟机]Java内存模型

Java内存模型 概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能了。在许多场景下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统的速度差距太大,大量的时间都花费在磁盘I/O、网络…

深入理解 DB-GPT

DB-GPT 项目介绍 DB-GPT是一个开源的AI原生数据应用开发框架(AI Native Data App Development framework with AWEL(Agentic Workflow Expression Language) and Agents)。目的是构建大模型领域的基础设施,通过开发多模型管理(SMMF)、Text2SQL效果优化、RAG框架以及优化、Mult…

2024年国内最经典好用的5款项目管理软件工具助你一路长虹

目前市场上的项目管理软件众多,但是它们也都有一些共同的功能及特点。比如任务和进度管理、资源分配、财务监控、风险评估、协作增强以及报告和洞察力等。这些功能不仅提供了强大的工具来确保项目的高效执行和按时交付,而且还为团队成员和管理者提供了实时的数据和信息,帮助…

「代码随想录算法训练营」第六天 | 哈希表 part2

454. 四数相加 II题目链接:https://leetcode.cn/problems/4sum-ii/ 题目难度:中等 文章讲解:https://programmercarl.com/0454.四数相加II.html 视频讲解: https://www.bilibili.com/video/BV1Md4y1Q7Yh 题目状态:没思路思路:创建一个unordered_map<int, int>类型的…

C#和VB.NET连接Access

一、直接通过软件连接Access表 1:新建一个windowsForm工程。2:打开"检视\伺服器总管\资料连接"后,右击"资料连接"后打开"连接资料连接",选择正确的资料来源与资料库档名,若有密码请输入正确的密码,如无,则不输入。3:点击"测试连接&qu…

一对一关联

一对一关系实际上是通过建立双向关系的一对多关系的基础上转化而来。比如:一个用户对应一张身份证,一张身份证属于一个用户。 class IdCard(Base): """省份证的模型类, 它和员工之间是一对一的关联关系""" __tablename__ = t_id_card id: Map…

CSS minification error: Lexical error on line 1:Unrecognized text

删除node_modules 重新安装,如果还不行,就复制一份别的能用的

【goreplay】python简单使用goreplay中间件功能

一、场景流量录制,需要对播放的流量进程定制化处理,那么可以使用中间件来实现二、官网 https://pypi.org/project/gor/三、编写中间件代码# coding: utf-8 import sys from gor.middleware import AsyncioGordef on_request(proxy, msg, **kwargs):proxy.on(response, on_res…

一对多和多对一关联

比如:作者和文章之间, 部门和员工之间都是一对多的关联关系。反过来就是:多对一的关联关系 1、定义外键约束 定义关系的第一步是创建外键。外键是(foreign key)用来在 A 表存储 B 表的主键值以便和 B 表建立联系的关系字段。因为外键只能存储单一数据(标量),所以外键总…