目录

1、yum安装LNMP环境

1.1、安装nginx软件

1.2、安装MySQL

1.3、安装PHP和php-mysql模块和php-fpm模块

1.4、提供php的测试页

1.5、修改nginx.conf,支持php访问

1.6、测试LNMP

2、roles角色

3、基于角色的方式部署LNMP

4、配置playbook创建LNMP构建的任务

4.1、创建相关目录

4.2、配置被管理主机

4.2.1、设置ssh免密连接

4.2.2、定义hosts文件

4.3、配置site.yml

4.4、配置webserver.yml,构建prepare角色

5、构建nginx角色

5.1、配置nginx的tasks

5.2、复制相应的安装包和模板到对应目录下

5.3、根据需要修改nginx的配置文件模板。(这里改的是work进程生成数和监听的端口)

5.4、构建nginx的handlers目录和vars/下的main.yml文件

6、 构建PHP角色

6.1、配置php的tasks

6.2、复制相应的安装包和模板到对应目录下

6.3、构建php的handlers目录下的main.yml文件

7、构建mysql角色

7.1、配置mysql的tasks

7.2、复制相应的安装包和模板到对应目录

7.3、构建mysql的handlers目录下的main.yml文件


本案例是通过rpm包部署LNMP环境(基于aliyun和epel源),如果要通过源码包部署的话,可以编写shell脚本,通过script模块进行批量部署LNMP。

1、yum安装LNMP环境

首先,我们可以在ansible服务器上安装LNMP环境,然后,再将配置文件通过ansible拷贝到远程主机上

1.1、安装nginx软件

[root@cong11 ~]# yum -y install nginx     #通过aliyun和epel源
[root@cong11 ~]# systemctl start nginx

测试访问nginx的默认测试页:

1.2、安装MySQL

[root@cong11 ~]# yum install -y mariadb-server  mariadb
[root@cong11 ~]# mkdir -p /data/mysql/data   #创建数据库保存目录
[root@cong11 ~]# chown -R mysql:mysql /data/mysql/  #修改权限
[root@cong11 ~]# vim /etc/my.cnf         #修改数据保存目录

[mysqld]
datadir=/data/mysql/data    #修改此行,其他参数保持默认即可

[root@cong11 ~]# systemctl start mariadb

1.3、安装PHP和php-mysql模块和php-fpm模块

[root@cong11 ~]# yum install -y php php-mysql php-fpm
[root@cong11 ~]# systemctl start php-fpm

1.4、提供php的测试页

[root@cong11 ~]# vim /usr/share/nginx/html/index.php

<?php
phpinfo();
?>

1.5、修改nginx.conf,支持php访问

[root@cong11 ~]# vim /etc/nginx/nginx.conf  #在server{}中添加标红部分的内容

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 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;
        index index.php index.html;
        include /etc/nginx/default.d/*.conf;

location / {
        }
        location ~ .*\.(php|php5)?$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            include fastcgi.conf;
        } 
        error_page 404 /404.html;
            location = /40x.html {
        }

error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}

重启nginx服务

[root@cong11 ~]# systemctl restart nginx

1.6、测试LNMP

确保已经出现上面的测试页,而且,要看到MySQL已经被整合进来了,才能进行下一步操作

2、roles角色

当我们刚开始学习运用 playbook 时,因为操作很多,所以很可能会把 playbook 写成一个很大的文件,慢慢你会发现,playbook的内容较为混乱,难以管理,怎么组织我们的Playbook才能让他们清晰明了,易于管理呢?也就是在这样的条件下,我们的Roles角色,才能体现出其功能。
    Roles相当于我们剧本当中的角色,每个角色都有不同的事情要做,也正是分工才体现出了每个角色不同的作用,当你需要做不同的事情时,只需要调用不同角色即可。
    比如一个互联网公司,想要研发新的软件时,就需要找产品去设计软件,找开发去研发软件,找测试去测试软件,找运维去维护软件,每一个角色都会完成各自的功能,这就是Role的作用。
    总结:
Roles 角色:以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等;相当于函数的调用把各个事件切割成片段来执行。
    估计对roles还是有一点点模糊吧,没关系,通过案例我们再来捋顺下们的思路

3、基于角色的方式部署LNMP

基于此案例我们先了解下Ansible自动化部署目录结构,当我们在做一个自动化部署的案例时,往往不会使用默认的配置项以及配置文件,都会单独创建自己的配置文件,也会根据功能不同,划分出不同的目录,因此,一个成熟的ansible项目会具备自己所需求的目录结构。

其中有文件有目录,我们一个个说明
    ansible.cfg 对于整个项目的配置文件
    hosts 定义主机的配置文件
    roles 定义角色的目录(名字不能修改)
    prepare 角色目录
    nginx 角色目录
    mysql 角色目录
    php 角色目录
    role_name/     #在相关角色目录下通常要创建如下目录
    files/:存储由copy或script等模块调用的文件,例如存放需要同步到远程服务器的源码文件及配置文件等。
    tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用;
    handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行“包含”调用;例如当服务的配置文件发生变化时需要进行的操作,比如:重启服务,重新加载配置文件。
    vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;其它的文件需要由main.yml进行“包含”调用;
    templates/:存储由template模块调用的模板文本。如用于执行lnmp相关配置文件的模板文件。
    meta/:角色定义,可留空。此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用;
    site.yml 整个项目的入口文件
    webserver.yml webserver分支的入口文件

注:这些目录、文件都需要自己创建

4、配置playbook创建LNMP构建的任务

4.1、创建相关目录

root@cong11 ~]# mkdir -p /ansible/lnmp/roles/{prepare,nginx,mysql,php}/{tasks,files,templates,vars,meta,handlers}
[root@cong11 ~]# touch /ansible/lnmp/ansible.cfg
[root@cong11 ~]# touch /ansible/lnmp/hosts
[root@cong11 ~]# touch /ansible/lnmp/site.yml
[root@cong11 ~]# touch /ansible/lnmp/webserver.yml

4.2、配置被管理主机

开始编辑各自的文件,首先是hosts文件(清单文件)

4.2.1、设置ssh免密连接

注:设置过请跳过

[root@cong11 ~]# ssh-keygen
[root@cong11 ~]# ssh-copy-id root@192.168.121.12
[root@cong11 ~]# ssh-copy-id root@192.168.121.13

4.2.2、定义hosts文件

[root@cong11 ~]# vim /ansible/lnmp/hosts

[nginx]
nginx01 ansible_ssh_host=192.168.121.12 ansible_ssh_port=22 ansible_ssh_user=root
nginx02 ansible_ssh_host=192.168.121.13 ansible_ssh_port=22 ansible_ssh_user=root

[mysql]
mysql01 ansible_ssh_host=192.168.121.12 ansible_ssh_port=22 ansible_ssh_user=root

[php]
php01 ansible_ssh_host=192.168.121.12 ansible_ssh_port=22 ansible_ssh_user=root
php02 ansible_ssh_host=192.168.121.13 ansible_ssh_port=22 ansible_ssh_user=root

[lnmp:children]
nginx
mysql
php

说明:
    是不是突然发现了一个不一样的组[lnmp:children],它的意思是,lnmp组由别的组成,具体成员是其他组的组名,这样当调用lnmp组时就会调用其他组内的组员了,同时要注意,lnmp组里的组员,要在lnmp之前声明。
    测试所有主机的连通性:

发现出现警告,原因是在执行命令是无法找到lnmp组,因为我们默认是用的是/etc/ansible/hosts文件,这个文件中并没有定义lnmp组,我们的lnmp组存在于我们ansible项目根目录(/ansible/lnmp/)的hosts文件内,如果想使用/ansible/lnmp/路径下的hosts文件,需要修改ansible.cfg配置文件,修改成这样:

[root@cong11 lnmp]# vim /ansible/lnmp/ansible.cfg

[defaults]
host_key_checking = True
inventory = ./hosts

注意,如果要使用相对路径,或者要使用非/etc/ansible/ansible.cfg,则必须要在项目的根目录下执行命令

那为什么/etc/ansible/ansible.cfg和hosts不生效了呢?而是在本地的配置文件生效了呢?原因是Ansible默认有个配置文件查找顺序,Ansible在执行程序时查找配置文件的顺序是 ANSIBLE_CONFIG (环境变量) -> ansible.cfg (当前目录中) -> ~/.ansible.cfg (家目录中的) -> /etc/ansible/ansible.cfg,从这个顺序中,我们可以看出,我们的配置文件,位于当前目录,是Ansible查找的第二个选项,因此,当他找到本地的配置文件后,就不会再向下查找了,所以我们本地的配置文件生效。
    又因为我们本地的配置文件中指定了Inventory的路径,所以针对于当前目录的配置文件来说,当前目录下的hosts文件生效,而不是/etc/ansible/hosts生效。

4.3、配置site.yml

现在我们已经调整好了配置,设置好了主机,接下里就开始写Roles以及Playbook,我们site.yml文件是一切任务的入口文件,因此我们从site.yml开始写。

[root@cong11 lnmp]# cat site.yml 

---
- import_playbook: webserver.yml

Import_playbook意为包含webserver.yml这个文件,当执行到site.yml文件中的这一行时,就会跑去执行webserver.yml里面的内容,这样我们的项目将会更加模块化,利于管理。

4.4、配置webserver.yml,构建prepare角色

webserver.yml当中又要写些什么呢?webserver当中写的是要完成对应的模块功能需要的角色,也就是需要什么样的Role。
    例如:我们要完成lnmp项目的第一个role,也就是prepare角色(prepare角色主要任务是:远程主机配置yum源,关闭防火墙,关闭selinux),webserver.yml文件内容如下:

hosts:all的意思是,让所有主机去执行prepare这个Role,如果想要针对于组执行Role,那么就将all换成组名,如果针对于某个主机执行,就写主机的别名或者IP
    roles列表当中的prepare是指,我们要执行prepare这个Role,那么我们就需要在roles这个目录下创建一个叫做prepare的文件夹,保证我们的Role能够执行,我们roles选项下的名称就是我们在roles目录中文件夹的名称。

对于图上其他内容说明,gather_facts: True开启收集主机静态信息,如版本号,操作系统内容等,tags: prepare,对当前内容进行标记,也就是打标签,在执行时可以使用标签从指定位置开始向下执行,为测试节省时间
    prepare内容说明,存在两个目录,一个是tasks,执行对应任务的目录,一个是templates,进行模版文件复制的目录。

当执行到对应的Role时,Ansbile就会调用对应Role目下的Playbook,也就是调用我们的tasks,所以我们在对应的Role目录下都会存在一个叫做tasks的目录

tasks目录当中文件说明,main.yml,任务的入口文件,执行任务时从此文件开始执行,yum.yml、firewalld.yml、selinux.yml完成对应功能的目录

     目录内文件说明,我们把main.yml文件作为task执行的入口文件,帮助我们加载对应的功能,yum.yml文件用于配合yum源,firewalld.yml文件,关闭防火墙,selinux.yml执行关闭selinux。
    在执行tasks时,Ansible默认会找对应tasks下的main.yml文件,这个文件也就是我们说的tasks的入口文件,所有tasks都是从这个文件开始执行的,所以main.yml文件名不能改变。在main.yml当中我们写入我们要执行的内容即可

对于关键字段说明:
    import_tasks字段,是在main.yml文件当中导入相关功能文件的内容,来执行相关文件name字段,相当于对执行任务的说明

yum.yml文件要执行的内容:

firewalld.yml文件要执行的内容:

selinux.yml文件要执行的内容:

对于关键字段说明:
    template字段,指定模版文件,该文件必须存在于prepare角色目录下的templates目录中,起名需要加上.j2结尾,将templates下的文件复制到对应主机的对应目录下,src指定源文件,dest指定目标目录及复制到目录后改成什么名字。
    生成selinux配置文件的模板,并修改模板文件,永久禁用selinux

[root@cong11 lnmp]# cp /etc/selinux/config/ansible/lnmp/roles/prepare/templates/config.j2
 [root@cong11 lnmp]# vim /ansible/lnmp/roles/prepare/templates/config.j2

SELINUX=disabled  #将enforcing改为disabled

测试结果,需要再次注意,执行ansible-playbook时,需要到ansible项目的根目录下执行

    [root@cong11 ~]# cd /ansible/lnmp/[root@cong11 lnmp]# ansible-playbook site.yml

如果上述结果没有红色字体,体现出对应的errors字段,说明我们执行的任务无问题。
    到此为止我们对于项目的雏形已经有了,下面就是我们继续完善我们的项目,首先,在webserver.yml文件将我们要干的事情,全部用角色的身份填写完毕,然后注释掉暂时不执行的内容,以便后续修改。

5、构建nginx角色

Nginx角色说明,在nginx目录中除了和prepare目录中一样,具备的tasks和templates以外,还多一个目录叫做handlers,该目录使用来执行notify,handler功能的,后续说明该功能。另外还会用到files和vars目录。

5.1、配置nginx的tasks

tasks,templates下目录内容和prepare一样,就不再详细说明,只看内容即可,tasks当中的内容查看。

目录结构和功能与prepare类似,不再说明,查看文件内容
    main.yml文件内容如下:

install.yml文件内容如下:

config.yml文件内容如下:

说明:
    Ansible的template模块。该模块和copy模块作用基本一样,都是把某个文件复制到远端主机上,但是区别在于template模块可以获取变量的值,而copy则是原封不动的把文件内容复制过去。
    notify模块,在是在做消息通知,notify上面的内容如果执行成功,就会发出消息,通知notify下方的内容执行,如果上面的内容没有执行,就不会通知下面的内容,如何判断是否执行就看执行过程的返回结果,是changed还是ok,changed是执行了,ok是没执行。
    webpage.yml文件内容如下:

5.2、复制相应的安装包和模板到对应目录下

[root@cong11 ~]# vim /ansible/lnmp/roles/nginx/files/testdb.php

<?php
    $link=mysql_connect('192.168.1.12','zhangsan','123456');
    if ($link)echo "connection success......";
    mysql_close();
    ?>

[root@cong11 tasks]# cp /usr/share/nginx/html/index.php /ansible/lnmp/roles/nginx/files/
[root@cong11tasks]#cp/etc/nginx/nginx.conf/ansible/lnmp/roles/nginx/templates/nginx.conf.j2

5.3、根据需要修改nginx的配置文件模板。(这里改的是work进程生成数和监听的端口)

[root@cong11 tasks]# vim /ansible/lnmp/roles/nginx/templates/nginx.conf.j2

5.4、构建nginx的handlers目录和vars/下的main.yml文件

[root@cong11 tasks]# vim /ansible/lnmp/roles/nginx/handlers/main.yml

[root@cong11 tasks]# vim /ansible/lnmp/roles/nginx/vars/main.yml

打开nginx角色的注释

[root@cong11 lnmp]# vim webserver.yml

然后执行测试

[root@cong11 ~]# cd /ansible/lnmp/
[root@cong11 lnmp]# ansible-playbook site.yml -t nginx

测试访问192.168.1.12和192.168.1.13的测试页

6、 构建PHP角色

构建php任务,这里我们只用到了tasks,templates和handlers目录,tasks当中的内容查看。

6.1、配置php的tasks

main.yml文件内容:

[root@cong11 tasks]# vim main.yml

install.yml文件内容:

[root@cong11 tasks]# vim install.yml

config.yml文件内容:

6.2、复制相应的安装包和模板到对应目录下

[root@cong11 tasks]# cp /etc/php.ini /ansible/lnmp/roles/php/templates/php.ini.j2
[root@cong11 tasks]# cp /etc/php-fpm.conf /ansible/lnmp/roles/php/templates/php-fpm.conf.j2
[root@cong11 tasks]# cp /etc/php-fpm.d/www.conf/ansible/lnmp/roles/php/templates/www.conf.j2

6.3、构建php的handlers目录下的main.yml文件

打开php角色的注释

然后执行测试:

[root@cong11 ~]# cd /ansible/lnmp/
[root@cong11 lnmp]# ansible-playbook site.yml -t php

测试访问192.168.1.12和192.168.1.13的测试页index.php

7、构建mysql角色

构建mysql任务,这里我们只用到了tasks,templates和handlers目录,tasks当中的内容查看。

7.1、配置mysql的tasks

mysql相关配置,首先打开webserver.yml下,打开mysql角色的注释

打开注释后,仿照nginx配置,写mysql的配置文件,具体目录结构参考nginx,不与说明,具体内容略有变化,进行详解

main.yml文件内容:

install.yml文件内容:

说明:
    我们发现在安装数据库的同时,安装了一个叫装MySQL-python的包,这个包是在我们即将配置mysql时使用的,因为我们在配置mysql时调用了Ansible的mysql模块,所以需要由这个包对我们的操作进行支持,没有这个包我们无法使用Ansible的mysql模块。
    config.yml文件内容:

说明:
其他模块在前面已经说明过了,不再进行赘述,主要介绍涉及的新模块,分别是mysql_db,mysql_user模块
    mysql_db模块,对数据库当中的数据库进行操作,可以帮助我们完成create,drop,show等针对数据库的操作。
    mysql_user模块,针对于数据库当中用户进行操作,可以帮助我们完成,create,delete,select,grant等对于用户的操作。
    如果我们要操作数据库,那必不可少的过程是要登录数据库,对于这点,如果手动执行登录命令,复杂且不好管理,还好Ansible提供了数据库相关模块,对于数据库的操作,我们只需要调用相关模块即可
    在调用mysql_db和mysql_user时,统一会用到的参数login_host,login_user,login_password,login_port都是在指定登录时相关信息。
    对于mysql_db模块来说,name指定是数据库名,encoding指定创建数据库或操作数据库时使用的字符集,state是指对数据库进行什么样的操作,persent相当于创建数据库,import的是导入数据库,导入数据时使用的数据库文件由target指定,那么如果你想删除一个数据库,只需要将state由persent改成asbent。
    在调用mysql_user模块时,我们除了使用了登录的参数外,还有几个额外的参数,name创建或者操作用户时指定用户名,password指定创建用户的密码,host指定创建的用户能在哪里登录,priv指定创建出来的用户具备什么样的权限,state当中作用就和数据库一样了,persent表示创建,absent表示删除
    对mysql_user模块的priv书写方式为 “在哪个数据库上.对哪个表:有什么权限”的方式书写,举例:“*.*:all”表示,对所有数据库当中的所有表具备所有权限

7.2、复制相应的安装包和模板到对应目录

[root@cong11 ~]# cp /etc/my.cnf /ansible/lnmp/roles/mysql/templates/my.cnf.j2
[root@cong11 ~]# vim /ansible/lnmp/roles/mysql/templates/my.cnf.j2

[mysqld]
datadir=/data/mysql/data  #修改此行,其他参数保持默认即可

7.3、构建mysql的handlers目录下的main.yml文件

接下来执行测试

[root@cong11 ~]# cd /ansible/lnmp/
[root@cong11 lnmp]# ansible-playbook site.yml -t mysql

到192.168.121.12(数据库主机)上查看执行结果

访问之前复制到远程主机的testdb.php测试页

至此通过ansible playbook部署lnmp就完成了。

通过playbook部署LNMP环境相关推荐

  1. Docker部署LNMP环境

    Docker部署LNMP环境 172.16.10.0/24 Nginx:172.16.10.10 Mysql:172.16.10.20 PHP:172.16.10.30 网站的访问主目录:/wwwro ...

  2. tengine php环境,基于TENGINE部署LNMP环境

    基于tengine部署lnmp环境 Tengine-2.0.0 Mysql-5.6.15 Php-5.3.3 Centos-6.3 源码安装.配置mysql-5.6.15 从5.6开始,mysql用c ...

  3. Docker最佳实践-部署LNMP环境

    标签(linux): docker 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 环境准备 [root@docker ~]# cat /etc/redhat-r ...

  4. YUM部署高版本LNMP环境

    现状: yum epel源自带php mysql nginx版本较低不能满足测试和生产环境中程序性能及安全需求 LNMP-->Web环境快速部署 需求: yum源带的php版本也是5.4, 当我 ...

  5. 20分钟完成Mac上的 LNMP 环境部署,优雅·高效开发(Docker方式)

    一.前言 对于很多开发者来说,突然转到在 mac 系统开发,可能会非常难受,主要有以下几个原因 1.mac 上安装软件程序坑多,比如安装 PHP.Nginx,会存在很多使用 linux 或 windo ...

  6. ansible----playbook安装lnmp环境

    一.ansible--playbook介绍 playbook是由一个或多个"play"组成的列表.play的主要功能在于将事先归为一组的主机装扮成事先通过ansible中的task ...

  7. 用shell脚本一键搭建LNMP环境实战

    为了配合上一篇文字,这里先给大家整理一键如何部署LNMP环境; 其实在生产环境中中小企业也是很喜欢用这样的软件包,因为毕竟源码包安装步骤那么多谁也不能一步一步的在哪敲出来,在生产线上你说一台lnmp服 ...

  8. LNMP环境一键安装包

    LNMP,即Linux环境下的Nginx+MySQL+PHP的网站服务器架构.LNMP一键安装包可以在当前所有主流的Linux上安装LNMP生产环境,无需值守,一键自动实现编译.安装.提高性能.优化配 ...

  9. docker中lnmp访问php页面,Docker下部署LNMP工作环境的教程(详细步骤)

    本篇文章给大家带来的内容是关于Docker下部署LNMP工作环境的教程(详细步骤),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 普通PC环境也可以用以下配置,只是MYSQL那里换回 ...

最新文章

  1. 斯坦福大学新研究:声波、光波等都是RNN
  2. C#程序设计笔记(第九章)
  3. 分享十佳Web开发资源
  4. 何钦铭c语言程序设计第八章,c语言程序设计(第3版)何钦铭-颜-晖-第8章--指针
  5. 二进制包如何知道go 版本_gops 是怎么和 Go 的运行时进行交互的?
  6. mybatisplus新增返回主键_第17期:索引设计(主键设计)
  7. 独家披露51CTO被黑过程:数据库已小范围流传
  8. 使用第三方框架解耦的一种思路—简单工厂模式的运用
  9. Python基于共现提取《釜山行》人物关系
  10. 【UE4】UE4文件系统
  11. tftp服务器配置及说明
  12. php v9 用户头像,phpcms v9前台会员中心上传头像可getshell | CN-SEC 中文网
  13. mysql57免安装教程_mysql5.7免安装版配置教程
  14. IOS 新增戴口罩面容ID解锁
  15. 零钱兑换问题c语言编程,leetcode- 零钱兑换 II(背包问题-总结-复盘)
  16. 学习3D游戏建模线上和线下学习的区别有哪些?
  17. 上传文件- rz -be -y
  18. python科目真题_不止金融行业, 全民都在学Python
  19. 博客从CSDN迁移至简书啦
  20. 数字之积 (数位dp)

热门文章

  1. 女程序猿的苦恼:“26岁后,分手对我来说不是件容易的事情”
  2. 正直的人就一定吃亏吗?———林格谈创业的智慧与勇气(3)
  3. python运行mcmc为何老出错_为什么我的metropolis算法(mcmc)的python实现这么慢?
  4. 虫虫blog html教程,虫虫的成长历程
  5. “我只警告一次,下次我会直接忽略你发的垃圾,懂?”Linus 精彩炮轰语录集锦
  6. Git操作:reset
  7. 基于Python的图像分类 项目实践——图像分类项目的指导文档
  8. Android单元测试系列(1)-开篇
  9. uni-app 微信同声传译,实现AI语音功能(语音转文字,文字转语音,英汉互译
  10. Flex中如何创建放射线状填充列图(ColumnChart)图表的例子