第五周Ansible
一、简述ansible架构与常用模块
- Ansible是一个自动化的配置管理工具;即在一台主控端上执行一个剧本/命令,来实现管理多个被控端的配置;
- Ansible基于SSH,无需客户端,需要SSH免密环境;
- Ansible执行的任务的结果是幂等的;
- 功能基于模块化,使用不同模块实现相应的功能;
- Ansible的基础架构:
主机清单
需要进行配置管理的主机,即被控端;主机/主机组
剧本
一组需要完成的任务,可以理解为一套IT架构,是一门编程语言;
- hosts: test_host
tasks:
- name: install services #任务1
yum:
name:
state:
- name: confgure services #任务2
template:
src:
dest:
notify: #触发器
- test
- name: start services #任务3
systemd:
name:
state:
handlers: #触发执行的任务
- name: test
systemd:
name:
state:
~
核心模块
Ansible自带的功能模块,比如:
yum_repository:配置yum仓库
yum:安装软件
user:创建用户
group:创建组
copy:复制到被控端文件
template:复制文件到被控端(可以使用变量渲染)
systemd:管理服务
archive:打包
unarchive :解压
script:可在被控端执行脚本
file:创建文件/目录
lineinfie:在配置文件中插入内容
自定义模块
如果核心模块不足以完成某个功能,可以添加自定义模块
插件
完成某项功能补充
连接插件
默认使用SSH连接其他主机,可以支持其他的连接方式,所以需要连接插件
Ansible变量
-
变量的作用:
方便管理变化的值,制作模板文件,根据不同的主机中的变量值来执行不同的操作; -
读取变量的优先级
-
如何取变量:
debug模块可读取变量的值;
[root@manager project1]# cat get_fact.yml
- hosts: lvs
tasks:
- name: get hostname
debug:
msg: "{{ ansible_ens33.ipv4.address }}"
fact变量
fact存放各个主机的相关信息,比如主机名、ip地址、FQDN、CPU数量,内存等等…
查看:
ansible redis -m setup 查看所有fact变量
ansible redis -m setup -a “filter=address” 筛选
如何使用:
常用户jinjia2模板,对配置文件相关参数改成变量,运行playbook的时候,会根据变量返回相应的值,渲染到被控端;
jinjia2模板
使用template模块,可以在模板文件或者相关play中使用相应的语法,达到根据自己的需求去渲染不同的配置文件;
if语句:
{% if 条件表达式 %}
{% elif 条件表达式 %}
{% endif %}
for循环:
- name: {{ item }}
loop:
- bob
- alice
when:
- hosts: redis
tasks:
- name: install vim
yum:
name: vim
state: present
when: ansible_os_family == "RedHat"
- name: install apt
yum:
name: apt
state: prensent
when: ansible_os_family == "Debian"
二、使用ansible部署一个lamp
使用Ansible部署一个kodbox集群环境
-
拓扑:
-
Ansible部署模型
-
免密环境准备
[root@manager project1]# cat auto_key.sh
PASSWD=P@ssw0rd
for server in 201 202 211 212 221 222 230 231 232 240 241
do
/usr/bin/expect << EOF
set timeout 30;
spawn ssh-copy-id root@10.0.0.$server
expect {
"yes/no" { send "yes\n" ;exp_continue; }
"password:" { send "${PASSWD}\n";exp_continue }
}
expect eof
EOF
done
- 目录准备
.
├── base_modules
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── dns_modules
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ ├── named.conf.j2
│ └── zhangzhonghao.com.zone.j2
├── keepalive-lvs_modules
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── keepalived.conf.j2
├── kodcloud
│ ├── files
│ │ └── kodcloud.zip
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── kodcloud.conf.j2
├── lvs-rs-dr
│ ├── files
│ │ └── lvs-rs.sh
│ ├── handlers
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── mysql_modules
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
├── nfs_modules
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── exports.j2
├── php-fpm_modules
│ ├── files
│ │ └── php.zip
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ ├── php-fpm.conf.j2
│ ├── php.ini.j2
│ └── www.conf.j2
├── proxy_nginx_modules
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ ├── kodcloud.conf.j2
│ └── proxy_params.j2
├── redis_modules
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── redis.conf.j2
└── web_nginx_modules
├── files
├── handlers
│ └── main.yml
├── meta
├── tasks
│ └── main.yml
└── templates
└── nginx.conf.j2
- 定义变量
[root@manager project1]# cat group_vars/all
#ALL
user: www
group: www
#NFS
nfs_share_dirtory: ansible/data
nfsaccesshost: 10.0.0.0/24
user_id: 1001
group_id: 1001
#kodcloud
service_domain_name: kodcloud.zhangzhonghao.com
service_port: 80
web_site_directory: /code/kodcloud
#proxy
web_server01: 10.0.0.201
web_server02: 10.0.0.202
#keepalvied
cluster_vip: 10.0.0.199
cluster_port: 80
realserver_port: 80
#DNS
domain_name: zhangzhonghao.com
dns_filename: zhangzhonghao.com.zone
ns_domain_name: ns.zhangzhonghao.com
ns1_domain_name: ns1.zhangzhonghao.com
ns2_domain_name: ns2.zhangzhonghao.com
dns_master_ip: 10.0.0.240
dns_backup_ip: 10.0.0.241
2.1 BASE基础环境部署
tasks
[root@manager project1]# cat roles/base_modules/tasks/main.yml
- name: Add base repository
yum_repository:
name: base
description: BASE YUM repo
baseurl: https://repo.huaweicloud.com/centos/$releasever/os/$basearch/
gpgcheck: yes
gpgkey: https://repo.huaweicloud.com/centos/RPM-GPG-KEY-CentOS-7
- name: Add epel repository
yum_repository:
name: epel
description: EPEL YUM repo
baseurl: https://repo.huaweicloud.com/epel/7/$basearch
gpgcheck: yes
gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
- name: Add nginx repository
yum_repository:
name: nginx
description: NGINX YUM repo
baseurl: http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck: yes
gpgkey: https://nginx.org/keys/nginx_signing.key
when: ( ansible_hostname is match ("web*") or ansible_hostname is match ("proxy*") )
- name: install init packet
yum:
name: "{{ item }}"
state: present
loop:
- httpd-tools
- net-tools
- vim
- tree
- htop
- iftop
- iotop
- lrzsz
- sl
- wget
- unzip
- nmap
- nc
- psmisc
- dos2unix
- bash-completion
- bash-completion-extras
- sysstat
- rsync
- nfs-utils
ignore_errors: yes
- name: stop firewalld
systemd:
name: firewalld
state: stopped
enabled: no
- name: stop selinux
selinux:
policy: targeted
state: permissive
- name: disble
selinux:
state: disabled
- name: add init group
group:
name: "{{ group }}"
gid: "{{ group_id }}"
state: present
tags: create user
- name: add init user
user:
name: "{{ user }}"
uid: "{{ user_id }}"
group: "{{ group_id }}"
state: present
tags: create user
- name: Confgure gateway
lineinfile:
path: /etc/sysconfig/network-scripts/ifcfg-ens33
regexp: '^GATEWAY'
line: GATEWAY=10.0.0.7
2.2 应用环境部署
2.2.1 mysql_modules
tasks
[root@manager mysql_modules]# cat tasks/main.yml
- name: install mariadb
yum:
name: "{{ item }}"
state: present
loop:
- mariadb-server
- mariadb
- name: start mariadb
systemd:
name: mariadb
state: started
enabled: yes
- name: create user
mysql_user:
name: all
password: 123456
host: '%'
priv: '*.*:ALL'
state: present
- name: create database
mysql_db:
name: "{{ item }}"
state: present
loop:
- wordpress
- kodcloud
2.2.2 redis_modules
tasks
[root@manager project1]# cat roles/redis_modules/tasks/main.yml
- name: Install redis
yum:
name: redis
state: present
- name: Confgure redis
template:
src: redis.conf.j2
dest: /etc/redis.conf
owner: 'redis'
group: 'root'
mode: '0640'
notify:
- Restart redis
- name: Start redis service
systemd:
name: redis
state: started
enabled: yes
handlers
- name: Restart redis
systemd:
name: redis
state: restarted
2.2.3 nfs_modules
tasks
[root@manager roles]# cat nfs_modules/tasks/main.yml
- name: Install nfs server
yum:
name: nfs-utils
state: present
- name: Create dirctory
file:
path: /ansible/data
state: directory
owner: "{{ user }}"
group: "{{ group }}"
- name: Start nfs server
systemd:
name: "{{ item }}"
state: started
enabled: yes
loop:
- nfs
- rpcbind
- name: Configure nfs server
template:
src: exports.j2
dest: /etc/exports
owner: "{{ user }}"
group: "{{ group }}"
mode: "0644"
notify:
name: Restart nfs
handlers
[root@manager roles]# cat nfs_modules/handlers/main.yml
- name: Restart nfs
systemd:
name: nfs
templates
[root@manager roles]# cat nfs_modules/templates/exports.j2
{{ nfs_share_dirtory }} {{ nfsaccesshost }}(rw,all_squash,anonuid={{ user_id }},anongid={{ group_id }})
2.2.4 web_nginx_modules
tasks
[root@manager roles]# cat web_nginx_modules/tasks/main.yml
- name: Install nginx
yum:
name: nginx
state: present
- name: Confgure nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: "{{ user }}"
group: "{{ group }}"
mode: "0644"
notify:
- Restart nginx
- name: start nginx
systemd:
name: nginx
state: started
enabled: yes
handlers
[root@manager roles]# cat web_nginx_modules/handlers/main.yml
- name: Restart nginx
systemd:
name: nginx
state: restarted
template
[root@manager roles]# cat web_nginx_modules/templates/nginx.conf.j2
user {{ user }};
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 40960;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
2.2.5 php-fpm_modules
tasks
[root@manager roles]# vim php-fpm_modules/tasks/main.yml
- name: unzip ptacket
unarchive:
src: php.zip
dest: /opt/
- name: Install PHP
yum:
name: "{{ item }}"
state: present
loop:
- /opt/php/libevent-2.0.21-4.el7.x86_64.rpm
- /opt/php/libmcrypt-2.5.8-13.el7.x86_64.rpm
- /opt/php/libmemcached-1.0.16-5.el7.x86_64.rpm
- /opt/php/libX11-1.6.5-2.el7.x86_64.rpm
- /opt/php/libX11-1.6.7-2.el7.x86_64.rpm
- /opt/php/libX11-common-1.6.5-2.el7.noarch.rpm
- /opt/php/libX11-common-1.6.7-2.el7.noarch.rpm
- /opt/php/libXau-1.0.8-2.1.el7.x86_64.rpm
- /opt/php/libxcb-1.13-1.el7.x86_64.rpm
- /opt/php/libXpm-3.5.12-1.el7.x86_64.rpm
- /opt/php/mod_php71w-7.1.32-1.w7.x86_64.rpm
- /opt/php/pcre-devel-8.32-17.el7.x86_64.rpm
- /opt/php/php71w-cli-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-common-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-devel-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-embedded-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-fpm-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-gd-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-mbstring-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-mcrypt-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-mysqlnd-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-opcache-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-pdo-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-pear-1.10.4-1.w7.noarch.rpm
- /opt/php/php71w-pecl-igbinary-2.0.5-1.w7.x86_64.rpm
- /opt/php/php71w-pecl-memcached-3.0.4-1.w7.x86_64.rpm
- /opt/php/php71w-pecl-mongodb-1.5.3-1.w7.x86_64.rpm
- /opt/php/php71w-pecl-redis-3.1.6-1.w7.x86_64.rpm
- /opt/php/php71w-process-7.1.32-1.w7.x86_64.rpm
- /opt/php/php71w-xml-7.1.32-1.w7.x86_64.rpm
ignore_errors: yes
- name: Confgure PHP
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
loop:
- {src: php.ini.j2, dest: /etc/php.ini, mode: "0644"}
- {src: php-fpm.conf.j2, dest: /etc/php-fpm.conf, mode: "0644"}
- {src: www.conf.j2, dest: /etc/php-fpm.d/www.conf, mode: "0644"}
notify:
- Restart php-fpm
- name: start PHP-fpm
systemd:
name: php-fpm
state: started
enabled: yes
templates
[root@manager project1]# ll roles/php-fpm_modules/templates/
total 76
-rw-r--r-- 1 root root 4207 Jun 25 14:20 php-fpm.conf.j2
-rw-r--r-- 1 root root 62616 Jun 25 14:29 php.ini.j2
-rw-r--r-- 1 root root 398 Jun 27 10:45 www.conf.j2
handlers
[root@manager php-fpm_modules]# cat handlers/main.yml
- name: Restart php-fpm
systemd:
name: php-fpm
state: restarted
files
[root@manager files]# ls
php.zip
2.2.6 proxy_nginx_modules
tasks
[root@manager project1]# cat roles/proxy_nginx_modules/tasks/main.yml
- name: Configure website
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
loop:
- {src: kodcloud.conf.j2, dest: /etc/nginx/conf.d/kodcloud.conf, mode: "0644" }
- {src: proxy_params.j2, dest: /etc/nginx/proxy_params, mode: "0644" }
notify:
- Restart nginx
meta
[root@manager project1]# cat roles/proxy_nginx_modules/meta/main.yml
dependencies:
- { role: web_nginx_modules }
templates
- 负载均衡配置文件
[root@manager project1]# cat roles/proxy_nginx_modules/templates/kodcloud.conf.j2
upstream {{ service_domain_name }} {
{% for host in groups["web"]%}
server {{ host }}:{{ service_port }};
{% endfor %}
}
server {
listen {{service_port}};
server_name {{service_domain_name}};
location / {
proxy_pass http://{{service_domain_name}};
include proxy_params;
}
}
- nginx参数配置文件
[root@manager project1]# cat roles/proxy_nginx_modules/templates/proxy_params.j2
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
2.2.7 keepalive-lvs_modules
tasks
[root@manager project1]# cat roles/keepalive-lvs_modules/tasks/main.yml
- name: install keepalived
yum:
name: "{{ item }}"
state: present
loop:
- keepalived
- ipvsadm
- name: start keepalived
systemd:
name: keepalived
state: started
enabled: yes
- name: Confgure keepalived
template:
src: keepalived.conf.j2
dest: /etc/keepalived/keepalived.conf
mode: "0644"
notify:
- Restart keepalived
templates
[root@manager project1]# cat roles/keepalive-lvs_modules/templates/keepalived.conf.j2
global_defs {
router_id {{ ansible_hostname }}
}
vrrp_instance VI_1 {
{% if ansible_hostname == "lvs-master" %}
state MASTER
priority 120
{% elif ansible_hostname == "lvs-slave" %}
state BACKUP
priority 100
{% endif %}
interface ens33
virtual_router_id 55
advert_int 3
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
{{ cluster_vip }}
}
}
virtual_server {{ cluster_vip }} {{ cluster_port }} {
delay_loop 6
lb_algo wlc
lb_kind DR
perssisstence_timeout 5
protocol TCP
{% for realserver_ip in groups["proxy"]%}
real_server {{ realserver_ip }} {{ realserver_port }} {
weight 1
TCP_CHECK {
connect_port {{ realserver_port }}
connect_timeout 3
nb_get_retry 2
delay_beefore_retry 3
}
}
{% endfor %}
}
handlers
[root@manager project1]# cat roles/keepalive-lvs_modules/handlers/main.yml
- name: Restart keepalived
systemd:
name: keepalived
state: restarted
2.2.8 dns_modules
tasks
[root@manager project1]# cat roles/dns_modules/tasks/main.yml
- name: Install DNS server
yum:
name: "{{ item }}"
state: present
loop:
- bind
- bind-utils
- name: Confgure DNS server
template:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
mode: "{{ item.mode }}"
loop:
- {src: named.conf.j2, dest: /etc/named.conf, mode: "0640"}
- {src: zhangzhonghao.com.zone.j2, dest: /var/named/zhangzhonghao.com.zone, mode: "0644"}
notify:
- Restart DNS server
- name: start DNS server
systemd:
name: named
state: started
enabled: yes
templates
- named配置文件
options {
listen-on port 53 { localhost; };
listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
recursing-file "/var/named/data/named.recursing";
secroots-file "/var/named/data/named.secroots";
allow-query { any; };
/*
- If you are building an AUTHORITATIVE DNS server, do NOT enable recursion.
- If you are building a RECURSIVE (caching) DNS server, you need to enable
recursion.
- If your recursive DNS server has a public IP address, you MUST enable access
control to limit queries to your legitimate users. Failing to do so will
cause your server to become part of large scale DNS amplification
attacks. Implementing BCP38 within your network would greatly
reduce such attack surface
*/
recursion yes;
dnssec-enable yes;
dnssec-validation yes;
/* Path to ISC DLV key */
bindkeys-file "/etc/named.root.key";
managed-keys-directory "/var/named/dynamic";
pid-file "/run/named/named.pid";
session-keyfile "/run/named/session.key";
{% if ansible_hostname == "dns-master" %}
allow-transfer { {{ dns_backup_ip}};};
also-notify { {{ dns_backup_ip}};};
{% elif ansible_hostname == "dns-backup" %}
masterfile-format text;
{% endif %}
};
logging {
channel default_debug {
file "data/named.run";
severity dynamic;
};
};
zone "{{ domain_name }}" IN {
{% if ansible_hostname == "dns-master" %}
type master;
file "{{ dns_filename }}";
notify yes;
{% elif ansible_hostname == "dns-backup" %}
type slave;
file "slaves/{{ dns_filename }}";
masters { {{ dns_master_ip }}; };
{% endif %}
};
zone "." IN {
type hint;
file "named.ca";
};
include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";
- 数据库文件
[root@manager templates]# cat zhangzhonghao.com.zone.j2
$TTL 600
{{ domain_name }}. IN SOA {{ ns_domain_name }}. qq.zhangzhonghao.com. (
20210626
10800
900
604800
86400
)
{{ domain_name }}. IN NS {{ ns1_domain_name }}.
{{ domain_name }}. IN NS {{ ns2_domain_name }}.
{{ ns1_domain_name }}. IN A {{ dns_master_ip }}
{{ ns2_domain_name }}. IN A {{ dns_backup_ip }}
;;service
{{ service_domain_name }}. IN A {{ cluster_vip }}
2.2.9 lvs-rs-dr
tasks
[root@manager project1]# cat roles/lvs-rs-dr/tasks/main.yml
- name: Run script lvs-rs node
script:
cmd: /opt/lvs-rs.sh
脚本文件
[root@manager /]# cat /opt/lvs-rs.sh
#!/bin/bash
VIP=10.0.0.199
DEV=lo:0
cat >/etc/sysconfig/network-scripts/ifcfg-${DEV} << EOF
DEVICE=lo:0
IPADDR=${VIP}
NETMASK=255.0.0.0
ONBOOT=yes
NAME=loopback
EOF
systemctl restart network
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "1" >/proc/sys/net/ipv4/conf/default/arp_ignore
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "2" >/proc/sys/net/ipv4/conf/default/arp_announce
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
2.3业务环境
- kodbox
tasks
[root@manager project1]# cat roles/kodcloud/tasks/main.yml
- name: Create Vhost file
template:
src: kodcloud.conf.j2
dest: /etc/nginx/conf.d/kodcloud.conf
notify:
- Restart nginx
- name: Create website directory
file:
path: /code/kodcloud
state: directory
owner: "{{ user }}"
group: "{{ group }}"
mode: "0755"
- name: Copy website code
unarchive:
src: kodcloud.zip
dest: /code/kodcloud
owner: "{{ user }}"
group: "{{ group }}"
mode: "0777"
handlers
[root@manager project1]# cat roles/kodcloud/handlers/main.yml
- name: Restart nginx
systemd:
name: nginx
state: restarted
2.4 playbook
[root@manager project1]# cat site.yml
- hosts: all
roles:
- base_modules
tags: base
- hosts: mysql
roles:
- mysql_modules
tags: mysql
- hosts: redis
roles:
- redis_modules
tags: redis
- hosts: nfs
roles:
- nfs_modules
tags: nfs
- hosts: web
roles:
- web_nginx_modules
- php-fpm_modules
tags: web_nginx
- hosts: proxy
roles:
- proxy_nginx_modules
- lvs-rs-dr
tags: proxy
- hosts: lvs
roles:
- keepalive-lvs_modules
tags: lvs
- hosts: dns
roles:
- dns_modules
tags: dns
- hosts: web
roles:
- kodcloud
tags: kodcloud
2.5验证
-
访问kodcloud.zhangzhoanghao.com
-
断开主用LVS,访问kodclou.zhangzhonghao.com
-
断开一个proxy_nginx,访问kodcloud.zhangzhonghao,com