wenmo8 发布的文章

背景

公司项目适配多种数据库其中包含SAP Hana,由于有同事的数据库连接工具保存了某个在用的数据库的旧密码,导致时不时会被锁用户。通过查询官方文档已解决,这里统一记录一下。

禁用密码锁定方法

以下按系统管理员和普通用户的解法分别列出。

禁用SYSTEM管理员密码锁定

查找安装Hana目录的indexserver.ini,在
[password policy]
块下添加
password_lock_for_system_user = false
,重启Hana数据库。

禁用普通用户密码锁定

禁用所有普通用户密码锁定方法

查找安装Hana目录的indexserver.ini,在
[password policy]
块下添加
password_locktime = 0
,重启Hana数据库。

禁用部分普通用户密码锁定方法(推荐,不需重启Hana)

使用sql建一个用户组,设置该组用户的锁定时间为0,然后把要禁用锁定的用户加到这个组里。

-- 创建用户组,设置该组用户无密码锁定时间
CREATE USERGROUP UNLOCKED_PASSWORD_USER_GROUP SET PARAMETER 'password_locktime' = '0' ENABLE PARAMETER SET 'password policy';
-- 将需要禁用锁定的用户添加到该组
ALTER USER <your user> SET USERGROUP UNLOCKED_PASSWORD_USER_GROUP;

PS:已被锁定的用户需要执行SQL解锁:
ALTER USER <user_name> RESET CONNECT ATTEMPTS;

第一章
Trino
简介

1.
Trino
概述

Trino是一个分布式SQL查询引擎,旨在查询分布在一个或多个异构数据源上的大型数据集。如果使用的是数TB或数PB的数据,那么很可能使用的是与Hadoop和HDFS交互的工具。Trino被设计为使用MapReduce作业管道(如Hive或Pig)查询HDFS的工具的替代品,但Trino并不局限于访问HDFS。Trino可以而且已经扩展到对不同类型的数据源进行操作,包括传统的关系数据库和其他数据源,如Cassandra。

Trino旨在处理数据仓库和分析:数据分析,汇总大量数据并生成报告。这些工作负载通常被归类为联机分析处理(OLAP)。

说明:
不要误解Trino理解SQL的事实,因为它提供了标准数据库的功能。Trino不是一个通用的关系数据库。它不能取代MySQL、PostgreSQL或Oracle等数据库。Trino不是为处理在线事务处理(OLTP)而设计的。对于为数据仓库或分析而设计和优化的许多其他数据库也是如此。

2.
Trino架构

Trino是一个分布式查询引擎,可跨多个服务器并行处理数据。Trino服务器有两种类型,协调器(coordinators)和工作节点(workers)。以下部分介绍了这些服务器和Trino体系结构的其他组件。

Trino集群由一个coordinator和多个worker组成。用户通过SQL工具与coordinator连接。协调员与工人合作。coordinator管理workers。通过配置catalogs,coordinator 和 the workers访问已连接的数据源。

每个查询的执行都是状态操作,coordinator编排工作负载,它会将任务调度到workers中并行执行。每个Trino都运行在JVM实例中,并通过使用线程进一步将任务并行化。

用户使用客户端工具(如JDBC驱动或Trino CLI)连接到集群中的协调器,然后协调器(coordinator)就可以协调工作节点(worker)访问数据源。

协调器(coordinator)是一类处理用户查询请求并管理工作节点执行查询工作的服务器。工作节点(worker)是一类负责执行任务和处理数据的服务器。

协调器(coordinator)通常会运行一个节点发现服务,工作节点(worker)通过注册到该服务来加入集群。客户端、协调器(coordinator)和工作节点(worker)之间所有的通信和数据传输,都通过基于HTTP/HTTPS的REST服务交互。

第二章
Trino安装

1.
Trino环境要求

Linux操作系统:64位

Java运行时环境: Jdk21以及以上版本

Python版本: 2.6.x、2.7.x 或 3.x

2.
Trino部署

Trino 服务器可以安装和部署在许多不同的服务器上平台。用户通常部署由一个具有一个协调器和多个工作节点的集群。Trino支持如何部署方式:

(1) 部署Trino

(2) Docker容器中的Trino

(3) Trino on Kubernetes with Helm

(4) RPM包

下文介绍RPM包的部署方式。

1、下载 Trino 的RPM 软件包

Trino Server 436下载地址 :

https://repo1.maven.org/maven2/io/trino/trino-server-rpm/436/trino-server-rpm-436.rpm

Trino Cli 436下载地址:

https://repo1.maven.org/maven2/io/trino/trino-cli/436/trino-cli-436-executable.jar

2、使用命令安装软件包:rpm

rpm -ivh  trino-server-rpm-436.rpm  --nodeps

3、启动服务

service  trino  start ;

安装后可以使用service命令管理Trino服务器:

service  trino  [start|stop|restart|status]

命令

动作

start

将服务器作为守护程序启动,并返回其进程 ID。

stop

关闭以 或 开头的服务器。发送 SIGTERM 信号。

restart

停止然后启动正在运行的服务器,或启动已停止的服务器, 分配新的进程 ID。

status

打印状态行,即“已停止 pid”或“作为 pid 运行”。

4、验证服务是否正常

(1)在服务器上执行service  trino  status,看到Running as XXX说明服务启动成功。

(2)在服务器上执行jps,如果看到TrinoServer的进程说明启动成功。

(3)在浏览器中输入:http://ip:8080,如果出现登录页面,随意输入用户root,登录可以看到如下页面。

5、安装Trino客户端

下载之后将trino-cli-436-executable.jar改成trino-cli,并给trino-cli添加可执行权限

mv  trino-cli-436-executable.jar  trino-cli

chmod +x trino-cli

./trino-cli --server localhost:8080

3.
Trino目录结构

(1) /usr/lib/trino/lib/:包含运行产品所需的各种库。插件位于插件子目录中。

(2) /etc/trino:包含一般的trino配置文件,如node.properties、jvm.config、config.properties。目录配置位于目录子目录中。

(3) /etc/trino/env.sh:包含trino使用的Java安装路径,允许配置进程环境变量,包括secrets。

(4) /var/log/trino:包含日志文件。

(5) /var/lib/trino/data:数据目录的位置。Trino在此处存储日志和其他数据。

(6) /etc/rc.d/init.d/trino:包含用于控制服务器进程的服务脚本以及文件路径的启动器配置。

第三章
Trino连接器

1.
MySQL连接器

MySQL连接器允许在外部MySQL实例中查询和创建表。这可以用于连接不同系统(如MySQL和Hive)之间的数据,或两个不同MySQL实例之间的数据。

1.1.
要求

(1) MySQL 5.7、8.0 或更高版本。

(2) 从 Trino 协调器和工作线程到 MySQL 的网络访问。 端口 3306 是默认端口。

1.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  mysql.properties

connector.name=mysql

connection-url=jdbc:mysql://192.168.80.131:3306

connection-user=root

connection-password=Root@1234

这里主机要使用IP地址,不要使用主机名。

1.3.
登录客户端

(1)重启trino服务

service trino stop ; service trino start ;

或者

service trino restart ;

(2)登录客户端命令

./trino-cli --server localhost:8080

或者连接trino时可以设置默认的catalog(某个连接实例)和schema(数据库),这样可以直接查询表。

./trino-cli
http://
localhost:8080
/mysql/test

说明:mysql为catalog中配置的connector.name,test为需要连接的数据库名称。

1.4.
操作MySQL

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs;

(2)查看mysql下所有的schemas (对应为数据库)

show schemas from mysql;

如果连接失败,可以查看日志/var/log/trino/server.log

(3)查看数据库中的所有表

show tables from mysql.test;

(4)查询表数据

use mysql.test;

select * from mysql.test.tbl001 limit 10;

(5)插入数据

insert into tbl001(id,name) values(5,'55555');

select * from mysql.test.tbl001;

(5)修改数据

update tbl001 set name = 'xxxxx' where id = 5 ;

select * from mysql.test.tbl001 ;

(6)删除数据

delete from tbl001 where id = 5 ;

select * from mysql.test.tbl001;

(7)查看表结构和建表语句

desc tbl001;

show create table tbl001 ;

(8)退出客户端

quit; 或者exit;

补充内容:

(9) 通过trino-cli直接执行SQL(使用--execute选项)

./trino-cli http://localhost:8080/mysql/test --execute 'select * from mysql.test.tbl001'

./trino-cli http://localhost:8080 --execute 'use mysql.test ; select * from mysql.test.tbl001'

(10) 通过trino-cli执行SQL文件(-f选项)

vi  mysql_test.sql

use mysql.test;

select * from tbl001;

执行SQL文件:./trino-cli http://localhost:8080  -f  mysql_test.sql

2.
PostgreSQL连接器

PostgreSQL连接器允许在外部PostgreSQL数据库中查询和创建表。这可以用于连接不同系统(如PostgreSQL和Hive)之间的数据,或不同PostgreSQL实例之间的数据。

2.1.
要求

(1) PostgreSQL 11.x或更高版本。

(2) Trino协调员(coordinator)和工作节点(workers )对PostgreSQL的网络访问。默认端口是5432。

2.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  postgresql.properties

connector.name=postgresql

connection-url=jdbc:postgresql://192.168.80.131:5432/bdc01

connection-user=postgres

connection-password=postgres

这里主机要使用IP地址,不要使用主机名。

2.3.
登录客户端

重启trino服务:

service trino stop ; service trino start ;

或者

service trino restart ;

登录客户端命令:

./trino-cli --server localhost:8080

2.4.
操作PostgreSQL

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs;

(2)查看postgresql下所有的schemas (对应为数据库)

show schemas from postgresql;

如果连接失败,可以查看日志/var/log/trino/server.log

(3)查看数据库中的所有表

show tables from postgresql.public;

(4)查询表数据

use postgresql.public;

select * from postgresql.public.nation_test order by n_nationkey ;

(5)插入数据

insert into nation_test(n_nationkey,n_name,n_regionkey) values(99,'XXXXX',3);

select * from nation_test order by n_nationkey ;

(6)修改数据

update nation_test set n_name = 'YYYYY' where n_nationkey = 99 ;

select * from nation_test order by n_nationkey ;

(7)删除数据

delete from nation_test where n_nationkey = 99 ;

select * from nation_test order by n_nationkey ;

(8)查看表结构和建表语句

desc nation_test;

或者 show columns from nation_test ;

show create table nation_test ;

(9)退出客户端

quit; 或者exit;

3.
Oracle连接器

Oracle连接器允许在外部Oracle数据库中查询和创建表。连接器允许Trino连接不同数据库(如Oracle和Hive)或不同Oracle数据库实例提供的数据。

3.1.
要求

(1) Oracle 19或更高版本。

(2) Trino协调员(coordinator)和工作节点(workers )对Oracle的网络访问。默认端口是1521。

3.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  oracle.properties

connector.name=oracle

connection-url=jdbc:oracle:thin:@192.168.80.134:1521/orclpdb1

connection-user=dsjzx

connection-password=Dsjzx123

这里主机要使用IP地址,不要使用主机名。

这里连接使用的是服务名orclpdb1,不是SID。

3.3.
登录客户端

重启trino服务:

service trino stop ; service trino start ;

或者

service trino restart ;

登录客户端命令:

./trino-cli --server localhost:8080

3.4.
操作Oracle

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs;

(2)查看oracle下所有的schemas (对应为用户)

show schemas from oracle;

如果连接失败,可以查看日志/var/log/trino/server.log

(3)查看数据库中的所有表

show tables from oracle.dsjzx;

(4)查询表数据

use oracle.dsjzx;

select * from oracle.dsjzx.ora_test01;

说明:在Oracle中使用Number字段类型时,必须指定精度,即NUMBER(p)或者NUMBER(p, s)。否则该字段在Tirno中无法识别。

(5)插入数据

insert into ora_test01(tid,name) values(99,'XXXXX');

select * from ora_test01;

(6)修改数据

update ora_test01 set name = 'YYYYY' where tid = 99 ;

select * from ora_test01 ;

(7)删除数据

delete from ora_test01 where tid = 99 ;

select * from ora_test01 ;

(8)查看表结构和建表语句

desc ora_test01;

或者 show columns from ora_test01 ;

show create table ora_test01;

(9)退出客户端

quit; 或者exit;

4.
Kafka连接器

Kafka连接器允许使用Apache Kafka主题作为Trino中的表。每条消息在Trino中显示为一行。

主题可以是实时的,当行在数据到达时显示,在数据段被丢弃时消失。如果在一个查询中多次访问同一个表(例如:自联接),这可能会导致奇怪的行为。

Kafka连接器跨Workers并行地读取和写入来自Kafka主题的消息数据,以实现显著的性能提升。这种并行化的数据集大小是可配置的,因此可以根据特定需求进行调整。

4.1.
要求

(1) Kafka broker 版本 0.10.0 或更高版本。

(2) 从 Trino 协调器(coordinator)和工作节点(Worker)到 Kafka 节点的网络访问。  默认端口是9092。

4.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  kafka.properties

connector.name=kafka

kafka.table-names=mytest

kafka.nodes=hadoop01:9092,hadoop02:9092,hadoop03:9092

kafka.table-description-dir=/etc/trino/kafka

#kafka.hide-internal-columns=false

说明:

(1)kafka.table-description-dir=/etc/trino/kafka :kafka的主题文件目录指定,需要配置参数。其中包含一个或多个JSON文件(必须以.json结尾),其中包含表描述文件。

(2)kafka.hide-internal-columns=false :用于显示Kakfa隐藏的内部列名。默认值为true,不显示Kafka隐藏的内部列名。

4.3.
登录客户端

重启trino服务:

service trino stop ; service trino start ;

或者

service trino restart ;

登录客户端命令:

./trino-cli --server localhost:8080

4.4.
操作Kafka

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs

(2)查看kafka下所有的schemas

show schemas from kafka;

(3)查看kafka中的所有topic

show tables from kafka.default;

(4)查看topic的信息

use kafka.default;

desc mytest ;

(5)查询Topic数据

select * from mytest ;

(6)将Topic中的值映射到Trino的列

编辑表信息的json文件。

vi  /etc/trino/kafka/default.mytest.json

{

"tableName": "mytest",

"schemaName": "default",

"topicName": "mytest",

"message": {

"dataFormat": "csv",

"fields": [

{

"name": "id",

"mapping": "0",

"type": "VARCHAR"

},

{

"name": "name",

"mapping": "1",

"type": "VARCHAR"

}

]

}

}

然后重启Trino服务。

service trino restart ;

接着通过生产者向topic写入csv格式的数据,以逗号作为分隔符。

bin/kafka-console-producer.sh --broker-list hadoop01:9092 --topic mytest

最后查询topic中的数据。

插入数据(暂时未验证通过)

insert into mytest(id,name) values('1','tom');

5.
Hive连接器

Hive 连接器允许查询存储在
Apache Hive
数据仓库中的数据。

Hive是三个组件的组合:

(1) 不同格式的数据文件,通常存储在Hadoop分布式文件系统(HDFS)或AmazonS3等对象存储系统中。

(2) 关于如何将数据文件映射到架构和表的元数据。这些元数据存储在数据库中,如MySQL,并通过Hive元存储服务进行访问。

(3) 一种称为HiveQL的查询语言。这种查询语言是在分布式计算框架(如MapReduce或Tez)上执行的。

Trino只使用前两个组件:数据和元数据。它不使用HiveQL或Hive执行环境的任何部分。

5.1.
要求

(1) Hive 连接器需要
Hive 元存储服务
(HMS) 或兼容的实现 Hive 元存储,例如
AWS Glue

(2) 支持Apache Hadoop HDFS 2.x和3.x。

(3) 数据文件必须采用受支持的格式:ORC、Parquet、Avro、RCText (RCFile using ColumnarSerDe)、RCBinary (RCFile using LazyBinaryColumnarSerDe)、SequenceFile、JSON (using org.apache.hive.hcatalog.data.JsonSerDe)、CSV (using org.apache.hadoop.hive.serde2.OpenCSVSerde)、TextFile。

5.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  hive.properties

connector.name=hive

hive.metastore.uri=thrift://192.168.80.131:9083

hive.config.resources=/etc/trino/hadoop/core-site.xml,/etc/trino/hadoop/hdfs-site.xml

这里主机要使用IP地址,不要使用主机名。

5.3.
Hive准备数据

!connect  jdbc:hive2://192.168.80.131:10000

use default;

create table tbl001(id  bigint, name string);

insert into tbl001(id,name) values(1,'111111'),(2,'222222'),(3,'333333');

select * from tbl001;

5.4.
登录客户端

重启trino服务:

service trino stop ; service trino start ;

或者

service trino restart ;

登录客户端命令:

./trino-cli --server localhost:8080

5.5.
操作Hive

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs;

(2)查看hive下所有的schemas (对应为数据库)

show schemas from hive;

如果连接失败,可以查看日志/var/log/trino/server.log

(3)查看数据库中的所有表

show tables from hive.default;

(4)查看表结构

desc hive.default.tbl001;

(5)查看表的数据

use hive.default;

select * from hive.default.tbl001;

(6)插入数据

insert into tbl001 values(99,'999999');

select * from tbl001;

(7)修改表的数据

update tbl001  set name = 'XXXXXXX'  where id = 99 ;

提示说明:只有Hive事务表支持修改表的行。

在Hive中创建事务表,并导入数据

set hive.support.concurrency = true;

set hive.enforce.bucketing = true;

set hive.exec.dynamic.partition.mode = nonstrict;

set hive.txn.manager = org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;

set hive.compactor.initiator.on = true;

set hive.compactor.worker.threads = 1;

create table trans_tbl001(

id bigint,

name string

)

clustered by (id) into 2 buckets

stored as orc

TBLPROPERTIES('transactional'='true');

insert into trans_tbl001(id,name) values(1,'111111');

insert into trans_tbl001(id,name) values(2,'222222');

insert into trans_tbl001(id,name) values(3,'333333');

insert into trans_tbl001(id,name) values(99,'999999');

通过trino客户端查询数据

select * from  trans_tbl001 ;

通过trino客户端修改数据

update trans_tbl001 set name = 'XXXXXXX' where id = 99 ;

select * from  trans_tbl001 ;

(8)删除表的数据

delete from tbl001 where id = 99 ;

提示说明:只有Hive事务表支持修改表的行。

delete from trans_tbl001 where id = 99 ;

select * from trans_tbl001 ;

(9)查询建表语句

show create table trans_tbl001;

6.
Hudi连接器

Hudi 连接器支持查询
Hudi
表,暂不支持插入、修改、删除操作。

6.1.
要求

(1) Hudi版本0.12.3或更高版本。

(2) Trino协调员(coordinator)和工作节点(workers )对对Hudi存储的网络访问。

(3) 访问Hive元存储服务(HMS)。

(4) Trino协调员(coordinator)到HMS的网络接入。

(5) 以Parquet文件格式存储在支持的文件系统中的数据文件。

6.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  hudi.properties

connector.name=hudi

hive.metastore.uri=thrift://192.168.80.131:9083

这里主机要使用IP地址,不要使用主机名。

6.3.
Hudi准备数据

(1)Hudi与Spark集成(省略)

(2)启动Spark-sql

spark-sql \

--conf 'spark.serializer=org.apache.spark.serializer.KryoSerializer' \

--conf 'spark.sql.catalog.spark_catalog=org.apache.spark.sql.hudi.catalog.HoodieCatalog' \

--conf 'spark.sql.extensions=org.apache.spark.sql.hudi.HoodieSparkSessionExtension'

(3)创建Hudi表

create  database  hudi_db;

use  hudi_db;

create table hudi_mor_tbl (

id int,

name string,

price double,

ts bigint

) using hudi

tblproperties (

type = 'mor',

primaryKey = 'id',

preCombineField = 'ts'

);

(4)导入数据

insert  into  hudi_mor_tbl  select 99, 'a99', 20.0, 900;

6.4.
登录客户端

重启trino服务:

service trino stop ; service trino start ;

或者

service trino restart ;

登录客户端命令:

./trino-cli --server localhost:8080

6.5.
操作Hudi

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs;

(2)查看hudi下所有的schemas (对应为数据库)

show schemas from hudi;

如果连接失败,可以查看日志/var/log/trino/server.log

(3)查看数据库中的所有表

show tables from hudi.hudi_db;

(10)查看表结构

desc hudi.hudi_db.hudi_mor_tbl;

(11)查看表的数据

use hudi.hudi_db;

select * from hudi_mor_tbl;

(12)查看元数据表

select * from  "hudi_mor_tbl$timeline" ;

Hudi连接器为每个Hudi表公开一个元数据表。元数据表包含有关Hudi表的内部结构的信息。可以通过将元数据表名称附加到表名称上来查询每个元数据表:select * from "test_table$timeline"。

(13)Hudi连接器暂不支持insert、update、delete操作

7.
Iceberg连接器

Apache Iceberg是一种用于大型分析数据集的开放表格式。Iceberg连接器允许查询以Iceberg格式编写的文件中存储的数据,如Iceberg表规范中所定义的。

7.1.
要求

(1) Trino协调员(coordinator)和工作节点(workers )对分布式对象存储的网络访问。

(2) 访问Hive元存储服务(HMS)、AWS Glue目录、JDBC目录、REST目录或Nessie服务器。

(3) 在支持的文件系统上,以文件格式ORC或Parquet(默认)存储的数据文件。

7.2.
配置

在/etc/trino/catalog中创建一个example.properties的属性文件。

cd  /etc/trino/catalog

vi  iceberg.properties

connector.name=iceberg

iceberg.catalog.type=hive_metastore

hive.metastore.uri=thrift://192.168.80.131:9083

这里主机要使用IP地址,不要使用主机名。

7.3.
Iceberg准备数据

##登录hive客户端

hive

##创建数据库

create database iceberg_db ;

use iceberg_db;

##创建Iceberg表

SET iceberg.catalog.iceberg_hive.type=hive;

SET iceberg.catalog.iceberg_hive.uri=thrift://192.168.80.131:9083;

SET iceberg.catalog.iceberg_hive.clients=10;

SET iceberg.catalog.iceberg_hive.warehouse=hdfs://192.168.80.131:8020/data/warehouse/iceberg-hive;

CREATE TABLE iceberg_test001 (

id    int,

name  string,

birthday  date,

create_time  timestamp

)

PARTITIONED BY(provincial string,ds string)

STORED BY 'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'

TBLPROPERTIES('iceberg.catalog'='iceberg_hive');

##插入数据

INSERT INTO iceberg_test001  values

(10001, 'a10001', '2020-01-01', current_timestamp(),'99999999','20240226'),

(10002, 'a10002', '2012-04-18', current_timestamp(),'99999999','20240226'),

(10003, 'a10003', '2015-11-03', current_timestamp(),'99999999','20240226'),

(10004, 'a10004', '2013-08-27', current_timestamp(),'99999999','20240226');

##查询数据

select * from  iceberg_test001 ;

7.4.
登录客户端

重启trino服务:

service trino stop ; service trino start ;

或者

service trino restart ;

登录客户端命令:

./trino-cli --server localhost:8080

7.5.
操作Iceberg

7.5.1.
Trino自建表的操作

(1)显示所有的catalog (catalog目录下的properties文件名)

show catalogs;

(2)创建SCHEMA

CREATE  SCHEMA  iceberg.iceberg_hive

WITH (location='hdfs://192.168.80.131:8020/data/warehouse/iceberg-hive/');

(3)创建表

use iceberg.iceberg_hive ;

CREATE TABLE  example_test01 (

id  INTEGER,

name  VARCHAR,

birthday  DATE,

create_time  TIMESTAMP,

provincial  VARCHAR,

ds  VARCHAR

)

WITH (

format = 'PARQUET',

partitioning = ARRAY['provincial', 'ds'],

sorted_by = ARRAY['id']

);

(4)插入数据

insert into example_test01 values

(10001, 'a10001',cast( '2020-01-01' as date), current_timestamp,'99999999','20240226'),

(10002, 'a10002', cast('2012-04-18' as date), current_timestamp,'99999999','20240226'),

(10003, 'a10003',cast( '2015-11-03' as date), current_timestamp,'99999999','20240226'),

(10004, 'a10004',cast( '2013-08-27' as date), current_timestamp,'99999999','20240226');

select * from example_test01 ;

(5)修改数据

update example_test01 set name = 'XXXXXX' where id = 10004 ;

select * from example_test01 where id = 10004 ;

(6)删除数据

delete from example_test01 where id = 10004 ;

select * from example_test01 ;

(7)查看所有的表

show tables;

(8)查看表结构和建表语句

desc example_test01 ;

show create table example_test01;

测试在hive中是否可以读取该表的数据

select * from example_test01 ;

从中可以看到,通过Trino创建的表,在Hive中无法查询。

为什么?

Trino和Hive创建Iceberg表的序列化规则(ROW FORMAT SERDE)和存储格式(STORED BY)不同。

--通过Trino创建生成的Iceberg表:

CREATE EXTERNAL TABLE `example_test01`(

`id` int,

`name` string,

`birthday` date,

`create_time` timestamp,

`provincial` string,

`ds` string)

ROW FORMAT SERDE
'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'

STORED AS INPUTFORMAT
'org.apache.hadoop.mapred.FileInputFormat'

OUTPUTFORMAT
'org.apache.hadoop.mapred.FileOutputFormat'

LOCATION
'hdfs://192.168.80.131:8020/data/warehouse/iceberg-hive/example_test01-50b32dc5ec9247498ea7fb35d5f526bb'

TBLPROPERTIES (

'metadata_location'='hdfs://192.168.80.131:8020/data/warehouse/iceberg-hive/example_test01-50b32dc5ec9247498ea7fb35d5f526bb/metadata/00004-cad950c2-57be-4550-9add-c363c70ef484.metadata.json',

'previous_metadata_location'='hdfs://192.168.80.131:8020/data/warehouse/iceberg-hive/example_test01-50b32dc5ec9247498ea7fb35d5f526bb/metadata/00003-a6d3f156-0f4a-4450-a70b-d02bb1a75e97.metadata.json',

'table_type'='ICEBERG',

'transient_lastDdlTime'='1709000455');

--通过Hive创建的Iceberg表

CREATE TABLE `iceberg_test001`(

`id` int COMMENT 'from deserializer',

`name` string COMMENT 'from deserializer',

`birthday` date COMMENT 'from deserializer',

`create_time` timestamp COMMENT 'from deserializer',

`provincial` string COMMENT 'from deserializer',

`ds` string COMMENT 'from deserializer')

ROW FORMAT SERDE
'org.apache.iceberg.mr.hive.HiveIcebergSerDe'

STORED BY
'org.apache.iceberg.mr.hive.HiveIcebergStorageHandler'

LOCATION
'hdfs://bdc01/user/hive/warehouse/iceberg_db.db/iceberg_test001'

TBLPROPERTIES (

'bucketing_version'='2',

'current-schema'='{"type":"struct","schema-id":0,"fields":[{"id":1,"name":"id","required":false,"type":"int"},{"id":2,"name":"name","required":false,"type":"string"},{"id":3,"name":"birthday","required":false,"type":"date"},{"id":4,"name":"create_time","required":false,"type":"timestamp"},{"id":5,"name":"provincial","required":false,"type":"string"},{"id":6,"name":"ds","required":false,"type":"string"}]}',

'current-snapshot-id'='2017496957845643908',

'current-snapshot-summary'='{"added-data-files":"1","added-records":"4","added-files-size":"1953","changed-partition-count":"1","total-records":"4","total-files-size":"1953","total-data-files":"1","total-delete-files":"0","total-position-deletes":"0","total-equality-deletes":"0"}',

'current-snapshot-timestamp-ms'='1708941864398',

'default-partition-spec'='{"spec-id":0,"fields":[{"name":"provincial","transform":"identity","source-id":5,"field-id":1000},{"name":"ds","transform":"identity","source-id":6,"field-id":1001}]}',

'engine.hive.enabled'='true',

'external.table.purge'='TRUE',

'iceberg.catalog'='iceberg_hive',

'last_modified_by'='root',

'last_modified_time'='1708941860',

'metadata_location'='hdfs://bdc01/user/hive/warehouse/iceberg_db.db/iceberg_test001/metadata/00001-29819742-3acb-46c0-8234-d16a350f132e.metadata.json',

'previous_metadata_location'='hdfs://bdc01/user/hive/warehouse/iceberg_db.db/iceberg_test001/metadata/00000-4cf17717-07ae-44c2-9079-9b2c8f3e2503.metadata.json',

'snapshot-count'='1',

'table_type'='ICEBERG',

'transient_lastDdlTime'='1708941860',

'uuid'='164870ac-489f-4434-a34c-3ed50340ed34')

7.5.2.
已存在Iceberg表的操作

(1)查看iceberg下所有的schemas (对应为数据库)

show schemas from iceberg;

如果连接失败,可以查看日志/var/log/trino/server.log

(2)查看数据库中的所有表

show tables from iceberg.iceberg_db;

(3)查看表结构

desc iceberg.iceberg_db.iceberg_test001;

通过Hive创建的Iceberg表,在Trino中无法访问。为什么?

第四章
功能验证

1.
跨源关联计算

./trino-cli --server localhost:8080

--查询表数据

select * from mysql.test.tbl001

select * from postgresql.public.test001 ;

select * from kafka.default.mytest ;

select * from hive.default.tbl001;

select * from iceberg.iceberg_hive.example_test01;

--MySQL和postgreSQL关联

select

my.id,

my.name  mysql_name,

pg.name  pg_name,

kfk.name  kafka_name,

hv.name   hive_name,

icbg.name  iceberg_name

from  mysql.test.tbl001   my

inner join postgresql.public.test001   pg  on  my.id = pg.id

inner join  kafka.default.mytest  kfk   on  my.id = cast(kfk.id as bigint)

inner join  hive.default.tbl001  hv    on  my.id = hv.id

inner join  iceberg.iceberg_hive.example_test01  icbg  on my.id = icbg.id;

本文分享自华为云社区
《【开发者空间实践】云主机安装Docker并制作自定义镜像在ModelArts平台做模型训练》
,作者: 开发者空间小蜜蜂。

1.1 案例介绍

在AI业务开发以及运行的过程中,一般都会有复杂的环境依赖需要进行调测并固化。面对开发中的开发环境的脆弱和多轨切换问题,在ModelArts的AI开发最佳实践中,通过容器镜像的方式将运行环境进行固化,以这种方式不仅能够进行依赖管理,而且可以方便的完成工作环境切换。配合ModelArts提供的云化容器资源使用,可以更加快速、高效的进行AI开发与模型实验的迭代等。

本案例将指导开发者如何在云主机上安装Docker制作一个自定义模型镜像并在ModelArts平台使用这个镜像作模型训练。

1.2 免费领取云主机

如您还没有云主机,可点击
链接
,领取专属云主机后进行操作。

如您已领取云主机,可直接开始实验。

1.3 实验流程

说明:

  1. 在云主机上安装docker;

  2. 制作模型训练镜像并上传到SWR;

  3. 在云主机创建训练脚本,使用浏览器打开OBS服务,上传训练脚本;

  4. 在ModelArts平台创建训练作业完成模型训练。

1.4 实验资源

本次实验花费总计约
1元
,资源采取按需计费,
点击链接
,可根据步骤加入华为云沃土云创计划,申领云资源代金券,即可免费体验。体验结束后,请及时释放资源,避免产生多余费用,给您带来不便。

1.5 在云主机安装Docker

进入云主机后,点击左面菜单的“终端”按钮,打开命令行工具。

在命令行中输入以下命令安装Docker:

curl -fsSL get.docker.com -o get-docker.sh
	sh get-docker.sh

输入命令“sudo docker info” 确认Docker已经安装完毕。

接下来需要配置镜像加速,输入命令“vim /etc/docker/daemon.json”编辑docker配置文件,单击“i”键进入插入模式,然后输入以下内容,

{
"registry-mirrors": [ "https://a3cc4b6f1d0747bda78ca8d86e4c5419.mirror.swr.myhuaweicloud.com" ]
}

输入完成后,按“Esc”退出插入模式,再输入“:wq”保存文件,再输入“sudo systemctl restart docker”命令重启docker,然后输入命令“sudo docker info”查看,显示如下信息则表示镜像加速配置完成。

1.6 准备制作镜像的必要文件

确认安装好Docker以后,在当前目录使用命令“
mkdir -p context”创建文件夹

使用“cd context/”命令进入context文件夹。

使用“vim pip.conf”命令编辑
pip源文件pip.conf ,单击“i”键进入插入模式,输入如下内容,确认无误后单击ESC回到命令模式,使用“:wq”命令保存退出。

[global]
index-url = https://repo.huaweicloud.com/repository/pypi/simple
trusted-host = repo.huaweicloud.com
timeout = 120

使用wget命令下载
“torch*.whl ”文件,一共三个文件

wget https://download.pytorch.org/whl/cu111/torch-1.8.1%2Bcu111-cp37-cp37m-linux_x86_64.whl
wget https://download.pytorch.org/whl/torchaudio-0.8.1-cp37-cp37m-linux_x86_64.whl
wget https://download.pytorch.org/whl/cu111/torchvision-0.9.1%2Bcu111-cp37-cp37m-linux_x86_64.whl

使用“wget https://repo.anaconda.com/miniconda/Miniconda3-py37_4.12.0-Linux-x86_64.sh
”命令,下载Miniconda3 py37 4.12.0安装文件

将上述pip源文件、torch*.whl文件、Miniconda3安装文件放置在context文件夹内,完成上述操作后context文件夹内容如下。

context
├── Miniconda3-py37_4.12.0-Linux-x86_64.sh
├── pip.conf
├── torch-1.8.1+cu111-cp37-cp37m-linux_x86_64.whl
├── torchaudio-0.8.1-cp37-cp37m-linux_x86_64.whl
└── torchvision-0.9.1+cu111-cp37-cp37m-linux_x86_64.whl

使用“vim Dockerfile”创建编辑Dockerfile文件,填入以下内容

# 容器镜像构建主机需要连通公网
# 基础容器镜像, https://github.com/NVIDIA/nvidia-docker/wiki/CUDA
# 
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
# require Docker Engine >= 17.05
#
# builder stage
FROM nvidia/cuda:11.1.1-runtime-ubuntu18.04 AS builder

# 基础容器镜像的默认用户已经是 root
# USER root

# 使用华为开源镜像站提供的 pypi 配置
RUN mkdir -p /root/.pip/
COPY pip.conf /root/.pip/pip.conf

# 复制待安装文件到基础容器镜像中的 /tmp 目录
COPY Miniconda3-py37_4.12.0-Linux-x86_64.sh /tmp
COPY torch-1.8.1+cu111-cp37-cp37m-linux_x86_64.whl /tmp
COPY torchvision-0.9.1+cu111-cp37-cp37m-linux_x86_64.whl /tmp
COPY torchaudio-0.8.1-cp37-cp37m-linux_x86_64.whl /tmp

# https://conda.io/projects/conda/en/latest/user-guide/install/linux.html#installing-on-linux
# 安装 Miniconda3 到基础容器镜像的 /home/ma-user/miniconda3 目录中
RUN bash /tmp/Miniconda3-py37_4.12.0-Linux-x86_64.sh -b -p /home/ma-user/miniconda3

# 使用 Miniconda3 默认 python 环境 (即 /home/ma-user/miniconda3/bin/pip) 安装 torch*.whl
RUN cd /tmp && \
    /home/ma-user/miniconda3/bin/pip install --no-cache-dir \
    /tmp/torch-1.8.1+cu111-cp37-cp37m-linux_x86_64.whl \
    /tmp/torchvision-0.9.1+cu111-cp37-cp37m-linux_x86_64.whl \
    /tmp/torchaudio-0.8.1-cp37-cp37m-linux_x86_64.whl

# 构建最终容器镜像
FROM nvidia/cuda:11.1.1-runtime-ubuntu18.04

# 安装 vim和curl 工具(依然使用华为开源镜像站)
RUN cp -a /etc/apt/sources.list /etc/apt/sources.list.bak && \
    sed -i "s@http://.*archive.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list && \
    sed -i "s@http://.*security.ubuntu.com@http://repo.huaweicloud.com@g" /etc/apt/sources.list && \
    apt-get update && \
    apt-get install -y vim curl && \
    apt-get clean && \
    mv /etc/apt/sources.list.bak /etc/apt/sources.list

# 增加 ma-user 用户 (uid = 1000, gid = 100)
# 注意到基础容器镜像已存在 gid = 100 的组,因此 ma-user 用户可直接使用
RUN useradd -m -d /home/ma-user -s /bin/bash -g 100 -u 1000 ma-user

# 从上述 builder stage 中复制 /home/ma-user/miniconda3 目录到当前容器镜像的同名目录
COPY --chown=ma-user:100 --from=builder /home/ma-user/miniconda3 /home/ma-user/miniconda3

# 设置容器镜像预置环境变量
# 请务必设置 PYTHONUNBUFFERED=1, 以免日志丢失
ENV PATH=$PATH:/home/ma-user/miniconda3/bin \
    PYTHONUNBUFFERED=1

# 设置容器镜像默认用户与工作目录
USER ma-user
WORKDIR /home/ma-user

完成编辑后,按“Esc”键退出编辑模式,输入“:wq”命令保存文件。
完成操作后,使用“ll”命令查看context文件夹内容如下

context

├── Dockerfile

├── Miniconda3-py37_4.12.0-Linux-x86_64.sh

├── pip.conf

├── torch-1.8.1+cu111-cp37-cp37m-linux_x86_64.whl

├── torchaudio-0.8.1-cp37-cp37m-linux_x86_64.whl

└── torchvision-0.9.1+cu111-cp37-cp37m-linux_x86_64.whl

1.7 制作镜像并上传SWR

在context文件夹下,输入“sudo docker build . -t pytorch:1.8.1-cuda11.1”命令构建镜像。

此过程需要5-8分钟,可以先进行下面的步骤。

打开火狐浏览器,进入华为云首页,依次选择“产品”>“容器”>“容器镜像服务SWR”,进入服务页面,然后点击“控制台”进入SWR控制台页面。

点击右上角的“创建组织”按钮,输入组织名,点击“确定”。如果已经有可用的组织,此步骤可以跳过。

然后回到总览页面,点击上方的“登录指令”按钮,复制弹出的docker命令,在此命令前面加上“sudo ”然后在云主机的终端命令行输入,显示“Login Succeeded”则表示登录成功。

使用下列命令给新做好的镜像打标签

sudo docker tag pytorch:1.8.1-cuda11.1 swr.{区域参数}/{组织名称}/pytorch:1.8.1-cuda11.1

区域参数从登录指令中获取,如下图红框所示,组织名称也请替换为上面步骤创建的组织名。此处以华为云 华南-广州区为例

sudo docker tag pytorch:1.8.1-cuda11.1 swr.cn-south-1.myhuaweicloud.com/ai-test/pytorch:1.8.1-cuda11.1

使用下列命令将镜像上传到SWR

sudo docker push swr.{区域参数}/{组织名称}/pytorch:1.8.1-cuda11.1

区域参数从登录指令中获取,如下图红框所示,组织名称也请替换为上面步骤创建的组织名。此处以华为云 华南-广州区为例

sudo docker push swr.cn-south-1.myhuaweicloud.com/ai-test/pytorch:1.8.1-cuda11.1

完成镜像上传后,在容器镜像服务控制台的“我的镜像”页面可查看已上传的自定义镜像。

1.8 创建OBS桶和文件夹并上传训练脚本

在华为云首页,依次选择“产品”>“存储”>“对象存储服务OBS”,进入服务页面,然后点击“购买”进入资源包购买页面。

按照如下规格购买:

购买完成后,在控制台页面左面的菜单中,点击“桶列表”。

然后点击右上角“创建桶”按钮,进入创建页面,

按照如下规格创建:

创建好桶后,就可以在桶列表页面看到,点击桶的名称链接进入桶的详情页。

点击“新建文件夹”按钮,创建一个名为“
pytorch”的文件夹,在此文件夹下再创建两个子文件夹,分别命名“log”和“
demo-code”。Demo-code文件夹存放训练脚本,log文件夹存放训练日志。

回到命令行窗口,在context文件夹下,使用vim
pytorch-verification.py命令新建编辑训练脚本,单击“i”键进入插入模式,输入如下内容,确认无误后单击ESC回到命令模式,使用“:wq”命令保存退出。

import torch
import torch.nn as nn

x = torch.randn(5, 3)
print(x)

available_dev = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
y = torch.randn(5, 3).to(available_dev)
print(y)

新建好脚本后,回到OBS控制台页面,进入到demo-code文件夹,将脚本上传到demo-code文件夹下。

点击“添加文件”,在/developer/context目录下,选择刚刚创建的
pytorch-verification.py文件,点击“打开”,完成上传。

1.9 在ModelArts上创建训练作业

在华为云首页,依次选择“产品”>“人工智能”>“AI开发平台ModelArts”,进入服务页面,点击“控制台”按钮,进入控制台页面。

第一次使用ModelArts平台,会提示权限不足,需要授权OBS服务和SWR服务。

点击上面红框的“此处”的超链接,进入授权委托页面,选择“新增委托”,权限配置选择“普通用户”,然后点击“创建”按钮即可。重新回到ModelArts控制台页面,提示权限不足的红框就消失了,可以正常使用了。

在左侧导航栏中选择“模型训练 > 训练作业”,默认进入“训练作业”列表。

按照如下表格填入参数信息:

训练作业创建完成后,后台将自动完成容器镜像下载、代码目录下载、执行启动命令等动作。

训练作业一般需要运行一段时间。

训练完成后,在OBS服务,我们创建的桶和log文件夹下找到训练日志并下载下来,在下载的日志文件中搜索关键字:tensor,看到如下信息表示训练成功。

至此,实验完成。

在移动应用开发日益火爆的今天,自动化测试成为了确保应用质量和用户体验的关键环节。Appium 作为一款广泛应用的移动应用自动化测试工具,为测试人员所熟知。然而,在不同的测试场景和需求下,还有许多其他优秀的工具可供选择。本文将为您介绍 7 个强大的 Appium 替代工具,助力您的移动应用自动化测试工作。

1、Calabash

Calabash(
https://github.com/calabash/calabash
)是一款用于移动应用程序的自动验收测试框架,可媲美Selenium WebDriver。它专为触屏设备上的应用程序提供API,支持iOS和Android平台。

Calabash的主要特点包括:

  • 触屏交互:专为触屏设备设计,提供了丰富的API来模拟用户交互。
  • 跨平台支持:可以在iOS和Android设备上运行测试。
  • 易于集成:可以与持续集成(CI)工具集成,实现自动化测试流程的自动化。

Calabash特别适合需要进行复杂用户交互和验收测试的移动应用。

2、Kobiton

Kobiton(
https://kobiton.com
)是一个基于云的平台,提供了对移动设备的全面测试支持,无论是手动测试还是自动化测试。

它的主要优势包括:

  • 真实设备测试:Kobiton不需要使用模拟器,完全可以在真实设备上运行测试,这确保了测试结果的准确性和可靠性。
  • 跨平台支持:支持iOS和Android设备,以及移动浏览器。
  • 无需额外驱动:作为一个基于云的平台,使用Kobiton无需安装额外的驱动程序和支持应用程序。
  • 支持多种测试技术:Kobiton完全支持Appium、Selenium WebDriver和Katalon技术,这意味着使用者无需学习额外的编程语言来运行测试。
  • 友好的用户界面:操作步骤简单易懂,便于快速浏览和测试管理。

Kobiton特别适用于需要在真实设备上进行大规模测试的场景,提供了高效和可靠的测试解决方案。

3、Robotium

Robotium(
https://robotium.com
)是一款用于Android应用程序的自动化测试框架,支持混合和原生应用程序。

其主要特点包括:

  • 支持原生和混合应用:可以轻松为Android应用程序编写自动化和black-box(黑盒)用户界面测试。
  • 跨活动测试:在Robotium的支持下,测试人员可以跨越多个Android活动系统编写应用、测试场景及功能。
  • 易于使用:提供了简单易用的API,使得开发者能够快速编写测试脚本。

Robotium特别适合需要进行复杂用户交互和跨活动测试的Android应用。

4、Airtest

Airtest(
http://airtest.netease.com/
)是一款基于Python编写的移动应用自动化测试框架,适用于iOS和Android平台。它采用图像识别技术定位元素,使测试用例编写更加简单。

主要特点有:

  • 支持图像识别、OCR识别等定位元素方式;
  • 丰富的API,满足各种测试场景;
  • 易于上手,降低测试人员的学习成本。

5、Macaca

Macaca(
https://macacajs.github.io/zh/
)是一款面向多端的自动化测试解决方案,支持iOS、Android、Web等平台。这意味着开发人员和测试人员可以使用同一套测试脚本在不同的移动设备操作系统上进行自动化测试,无需为每个平台单独编写测试代码。同时它采用Node.js编写,具有跨平台、易扩展等优点。

主要特点有:

  • 支持多种编程语言编写测试用例;
  • 强大的元素定位能力
  • 支持多种测试类型
  • 丰富的插件生态系统
  • 易于与持续集成工具集成。

6、Espresso

Espresso 是由 Google 开发的一款专门用于 Android 应用自动化测试的框架。

它具有以下特点:

  • Espresso 提供了简洁且易于使用的 API,测试人员可以快速编写测试用例。
  • 强大的同步机制,Espresso 内置了强大的同步机制,能够自动等待应用的 UI 元素处于可交互状态后再执行操作,大大减少了因异步加载导致的测试失败。
  • 与 Android 开发环境紧密集成:由于它是 Google 为 Android 生态量身打造的,所以与 Android Studio 等开发工具的集成度极高。这使得开发人员在进行应用开发的同时,可以方便地编写和运行自动化测试用例,实现开发与测试的无缝衔接。

适用场景:适用于 Android 应用的功能测试和 UI 测试,尤其在开发团队对 Android 开发环境熟悉且追求高效测试编写和执行的情况下,Espresso 是一个绝佳的选择。

7、XCUITest

XCUITest 是苹果官方推出的用于 iOS 应用自动化测试的框架。

其优势体现在以下几个方面:

  • 原生支持:作为苹果原生的测试框架,它对 iOS 系统和应用的特性支持非常全面。能够深入到 iOS 应用的内部机制,对各种原生 UI 组件进行精确的操作和验证。
  • 性能优化:在 iOS 设备上运行时,XCUITest 经过了高度的性能优化。它能够高效地利用设备资源,快速执行测试用例,减少测试时间。同时,它与 Xcode 紧密集成,便于开发人员在开发过程中进行调试和测试。
  • 可扩展性:支持使用第三方库和工具进行扩展,测试人员可以根据项目的特殊需求,引入额外的功能模块。例如,结合一些图像识别库,可以实现对应用中复杂图形界面元素的识别和操作。

适用场景:专门针对 iOS 应用的自动化测试,无论是在开发 iOS 应用的功能测试、UI 测试,还是在持续集成环境中对 iOS 应用进行自动化验证,XCUITest 都是首选工具。

前言

本文将详细介绍ansible-playbook中roles的各种用法,它允许你将相关的任务、变量、处理器、文件和模板等集合在一起,以便于在不同的项目中复用

环境准备

组件 版本
操作系统 Ubuntu 22.04.4 LTS
ansible 2.17.6

基本用法

文件结构

.
├── deploy.hosts
├── deploy.yaml
└── roles
    └── base
        └── tasks
            └── main.yaml

  • deploy.hosts作为目标机器的列表文件
    ▶ cat deploy.hosts
    10.22.11.166
    
  • deploy.yaml作为入口文件
    ▶ cat deploy.yaml
    - name: deploy
      hosts: all
      remote_user: wilson
      gather_facts: no
      vars:
        ansible_ssh_pass: '123456'
        ansible_python_interpreter: /usr/bin/python3
      roles:
        - base
    

    • name:指定作业的名字:deploy
    • hosts:
      all
      代表deploy.hosts文件中所有的机器(也可以指定机器的分类信息)
    • remote_user:目标机器的登录用户
    • gather_facts: 是否需要采集目标机器的基本数据,默认采集。脚本指定的是不采集,为了提高执行速度
    • vars.ansible_ssh_oass:目标机器登录用户的密码
    • vars.ansible_python_interpreter:目标机器python3的路径
    • roles:指定本次作业所使用的角色
      base
  • roles目录作为ansible-playbook中一系列作业任务的集合,其中一个集合的名字叫做
    base
    • tasks中的main.yaml作为
      base
      的入口文件
      ▶ cat roles/base/tasks/main.yaml
      - name: first
        command: echo 'hello world'
      

      • base
        当前只有1个任务,就是登录到目标机器,执行
        hello world

运行

▶ ansible-playbook -i deploy.hosts deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
changed: [10.22.11.166]

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在屏幕上显示执行结果

需要改造
roles/base/tasks/main.yaml

▶ cat roles/base/tasks/main.yaml
- name: first
  command: echo 'hello world'
  register: display_result
- name: display
  debug:
    msg: "{{ display_result }}"

把结果放入变量
display_result
,然后通过模版语言打印出来,并且是json格式的

运行:

▶ ansible-playbook -i deploy.hosts deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
changed: [10.22.11.166]

TASK [base : display] ********************************************************************************************
ok: [10.22.11.166] => {
    "msg": {
        "changed": true,
        "cmd": [
            "echo",
            "hello world"
        ],
        "delta": "0:00:00.002740",
        "end": "2024-11-19 07:22:22.226036",
        "failed": false,
        "msg": "",
        "rc": 0,
        "start": "2024-11-19 07:22:22.223296",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "hello world",
        "stdout_lines": [
            "hello world"
        ]
    }
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

引用环境变量

将操作系统的环境变量传入,可以通过
lookup
来引用,比如:要使用PATH,可以通过
lookup('env', 'PATH')

改造roles/base/tasks/main.yaml

▶ cat roles/base/tasks/main.yaml
- name: first
  debug:
    msg: "{{ lookup('env', 'PATH') }}"

运行:

▶ ansible-playbook -i deploy.hosts deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "/home/wilson/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/usr/local/go/bin:/usr/local/go/bin"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

使用ansible变量

这里的ansible变量,其中一部分ansible默认的变量,一部分是ansible运行的时候,会默认去采集目标机器的基本信息,比如操作系统、cpu、内存、磁盘等等的基本信息

部分内置变量

变量名 描述
inventory_hostname 当前任务执行的主机名(来自 Inventory 文件)
ansible_facts 包含所有收集到的主机事实(facts)
hostvars 所有主机变量的集合,包含当前和其他主机

采集目标机器的基本信息

需要把之前采集ansible基本信息的开关打开
gather_facts: yes
,打开之后会牺牲运行速度

改造roles/base/tasks/main.yaml

- name: first
  debug:
    msg: "{{ hostvars }}"

运行:

由于数据量太大,只展示部分,并且json格式,可以直接拿想要的值

▶ ansible-playbook -i deploy.hosts deploy.yaml

PLAY [deploy] ******************************************************************

TASK [Gathering Facts] *********************************************************
ok: [10.22.11.166]

TASK [base : first] ************************************************************
ok: [10.22.11.166] => {
    "msg": {
        "10.22.11.166": {
            "ansible_all_ipv4_addresses": [
                "10.22.11.166"
            ],
            "ansible_all_ipv6_addresses": [
                "fe80::a00:27ff:fef6:82c4"
            ],
            "ansible_apparmor": {
                "status": "enabled"
            },
            "ansible_architecture": "x86_64",
            "ansible_bios_date": "12/01/2006",
            "ansible_bios_vendor": "innotek GmbH",
            "ansible_bios_version": "VirtualBox",
            "ansible_board_asset_tag": "NA",
            "ansible_board_name": "VirtualBox",
            "ansible_board_serial": "NA",
            "ansible_board_vendor": "Oracle Corporation",
            ...
            "inventory_dir": "/home/wilson/workspace/ansible",
            "inventory_file": "/home/wilson/workspace/ansible/deploy.hosts",
            "inventory_hostname": "10.22.11.166",
            "inventory_hostname_short": "10.22.11.166",
            "module_setup": true,
            "playbook_dir": "/home/wilson/workspace/ansible"
        }
    }
}

PLAY RECAP *********************************************************************
10.22.11.166               : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

是否采集目标的基本信息

上面已经演示过,只需要
gather_facts: yes
即可

从命令行传入变量

ansible-playbook可以通过
-e
传入变量使用

▶ cat roles/base/tasks/main.yaml
- name: first
  debug:
    msg: "{{ app_name }} - {{ app_version }}"

运行:

▶ ansible-playbook -i deploy.hosts -e "app_name=prom app_version=1.0" deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************
ok: [10.22.11.166]

TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "prom - 1.0"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

动态选择host

1)将主机分组

修改deploy.hosts文件

▶ cat deploy.hosts
[ga]
10.22.11.166

[gb]
10.22.11.166
127.0.0.1

2)改造入口文件

▶ cat deploy.yaml
- name: deploy
  hosts: '{{h}}'
  remote_user: wilson
  gather_facts: no
  vars:
    ansible_ssh_pass: '123456'
    ansible_python_interpreter: /usr/bin/python3
  roles:
    - base

将hosts改在成为
'{{h}}'
,通过传入h变量来动态定义

3)运行

指定
h
为ga

▶ ansible-playbook -i deploy.hosts -e "h=ga" deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello world"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

指定
h
为gb

▶ ansible-playbook -i deploy.hosts -e "h=gb" deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello world"
}
ok: [127.0.0.1] => {
    "msg": "hello world"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
127.0.0.1                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

条件选择when

▶ cat roles/base/tasks/main.yaml
- name: first
  debug:
    msg: "version 1"
  when: version == '1'

- name: second
  debug:
    msg: "version 2"
  when: version == '2'

定义临时变量

通过
-e
传入的变量来产生临时变量

- name: first
  set_fact:
    tag: "hello-{{ version }}"

- name: second
  debug:
    msg: "{{ tag }}"

运行:

▶ ansible-playbook -i deploy.hosts -e "version=2" deploy.yaml

...

TASK [base : second] *********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello-2"
}

...

调用多个role

1)新增role: advance

.
├── deploy.hosts
├── deploy.yaml
└── roles
    ├── advance
    │   └── tasks
    │       └── main.yaml
    └── base
        └── tasks
            └── main.yaml

2)直接在入口文件deploy.yaml引用

.
├── deploy.hosts
├── deploy.yaml
└── roles
    ├── advance
    │   └── tasks
    │       └── main.yaml
    └── base
        └── tasks
            └── main.yaml

运行:

▶ ansible-playbook -i deploy.hosts -e "version=2" deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : first] **********************************************************************************************
ok: [10.22.11.166]

TASK [base : second] *********************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello-2"
}

TASK [advance : new-first] ***************************************************************************************
ok: [10.22.11.166] => {
    "msg": "new hello world"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

3)在roles
base
中引用
advance

▶ cat deploy.yaml
- name: deploy
  hosts: all
  remote_user: wilson
  gather_facts: no
  vars:
    ansible_ssh_pass: '123456'
    ansible_python_interpreter: /usr/bin/python3
  roles:
    - base

▶ cat roles/base/tasks/main.yaml
- name: base first
  debug:
    msg: "base {{ version }}"

- name: base second
  include_role:
    name: advance
  vars:
    role_pipe_from_base: "hello world from base"

- name: base third
  debug:
    msg: "{{ role_pipe_from_advance }}"
▶ cat roles/advance/tasks/main.yaml
- name: advance first
  debug:
    msg: "advance {{ version }}"

- name: advance second
  debug:
    msg: "{{ role_pipe_from_base }}"

- name: advance third
  set_fact:
    role_pipe_from_advance: "hello world from advance"

运行:

▶ ansible-playbook -i deploy.hosts -e "version=2" deploy.yaml

PLAY [deploy] ****************************************************************************************************

TASK [base : base first] *****************************************************************************************
ok: [10.22.11.166] => {
    "msg": "base 2"
}

TASK [base second] ***********************************************************************************************
included: advance for 10.22.11.166

TASK [advance : advance first] ***********************************************************************************
ok: [10.22.11.166] => {
    "msg": "advance 2"
}

TASK [advance : advance second] **********************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello world from base"
}

TASK [advance : advance third] ***********************************************************************************
ok: [10.22.11.166]

TASK [base : base third] *****************************************************************************************
ok: [10.22.11.166] => {
    "msg": "hello world from advance"
}

PLAY RECAP *******************************************************************************************************
10.22.11.166               : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

这个例子呈现了:

  • 传入变量
    version
    是共用的
  • 如何在role传递参数
  • 执行过程中定义的临时变量
    role_pipe_from_advance
    可以跨role持续
  • 多role执行是串行的

小结

  • 联系我,做深入的交流


至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...