看起来微服务与Kubernetes结合,已经没有本地部署JDK什么事来,但是……并不是哪家公司都有Kubernetes,普通公司单机跑Tomcat实在太多,有时候会单机跑SpringCloud的各种jar包,这些都需要部署JDK环境。
Oracle JDK提供yum包,装完以后连PATH都配置好了,看起来Ansible只需要用到copyyum模块就足够了,不过大部分时候,我们还是喜欢二进制部署,毕竟不是所有的服务器都是红帽系,那么,开始吧。

准备JDK包

之所以单独拿出来讲,实在是因为从Oracle下载JDK二进制包实在是太慢了,还好华为提供了镜像!

https://repo.huaweicloud.com/java/jdk/

随意选择版本下载,当然现在的企业开发基本是基于JDK1.8,选择个1.8的下载吧。

Ansible Playbook Roles文件编写

1 初始化项目

# 进入目录
cd /etc/ansible/roles

# 初始化项目
ansible-galaxy init install_jdk

# 下载JDk
cd install_jdk/files
wget https://repo.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz

2 流程分析

拷贝文件至机器后解压,然后在PATH目录中export即可。
需要使用到的模块:

  • unarchive
  • file
  • lineinfile
  • shell

其中有两个模块需要注意的,为什么用这俩:

2.1. unarchive

在常规逻辑中,拷贝解压用的是:

scp ...
tar ... -C ...

有时候可能需要考虑新建文件夹,还需要用到shell makdir或者file模块,其实直接用unarchive更为简单明了。

2.2.lineinfile

一般的教程对于export JAVA_HOME都是用的shell cat循环写入,如果写成这样的ansible playbook文件只运行一次还好,如果运行多次,每次都会新追加export!
一开始的思路是使用shell sed,将export内容全部清空,后来发现对于ansible来说,sed有两个模块可供选择,其中之一就是lineinfile。
lineinfile有很多参数,最简单的就是本次用到的,循环检测export,发现没有则增加,有则pass,而且检索全文,不会考虑顺序。

3.文件

Roles结构

tree install_jdk/
install_jdk/
├── defaults
│   └── main.yml
├── files
│   └── jdk-8u202-linux-x64.tar.gz
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── README.md
├── tasks
│   ├── config_profile.yml
│   ├── create_link.yml
│   ├── main.yml
│   └── unarchive_jdk.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml

8 directories, 12 files

file已经放入,其他所需的仅仅为tasks,分解为4个文件。

3.1. main.yml

path/install_jdk/tasks/main.yml
调用其他三个文件

---
# tasks file for install_jdk
- include: unarchive_jdk.yml
- include: create_link.yml
- include: config_profile.yml
3.2. unarchive_jdk.yml

path/install_jdk/tasks/unarchive_jdk.yml
使用unarchive模块将文件解压至目标机器的目录

---
- name: unarchive jdk files
  unarchive:
    src=jdk-8u202-linux-x64.tar.gz
    dest=/usr/local/bin
3.3. create_link.yml

path/install_jdk/tasks/create_link.yml
创建连接,方面设置PATH

---
- name: create link
  file:
    src=/usr/local/bin/jdk1.8.0_202
    dest=/usr/local/java
    state=link
3.4. config_profile.yml

path/install_jdk/tasks/config_profile.yml
循环检测写入export,然后最后执行source

---
- name: add java path to profile
  lineinfile: 
    path=/etc/profile
    line="{{ item }}"
  with_items:
    - export JAVA_HOME=/usr/local/java
    - export JRE_HOME=/usr/local/java/jre
    - export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
    - export PATH=$JAVA_HOME/bin:$PATH
- name: take effect
  shell: source /etc/profile  
3.5. ansible/workflow/install_jdk.yml

最后是ansible调用文件:

---
- hosts: need_install_jdk_node
  remote_user: root
  roles:
    - install_jdk

4.login与non-login

但是这么执行后,查看java版本则会遇到问题:

ansible node01 -m shell -a 'java -version'
node01 | FAILED | rc=127 >>
/bin/sh: java: 未找到命令non-zero return code

看起来没有找到java命令,那么查看java呢:

ansible node01 -m shell -a 'which java'
node01 | FAILED | rc=1 >>
which: no java in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin)non-zero return code

提示没有在PATH中找到。

问题排查

实际上ssh登录机器后发现PATH中确实有,那么可以理解,ssh与ansible登录过程并不相同,至少ansible没有用到/etc/profile文件,经过查询后发现ansible属于non-login登录,而ssh属于login登录。
对于non-login登录,默认按顺序加载以下文件:

  • ~/.bashrc
  • /etc/bashrc

而login登录则是按如下顺序加载以下文件:

  • /etc/profile
  • ~/.bash_profile
  • ~/.bashrc
  • /etc/bashrc

可以看到non-login并不加载/etc/profile~/.bash_profile文件,如果同时还想针对non-login程序,那么最好将配置写入~/.bashrc/etc/bashrc中。

什么是non-login

简而言之,不需要输入账号密码的登录即为non-login,那么以下三种行为都为non-login:

  • x-window 图形化界面
  • bash下输入bash
  • ssh无密码登录

4.多版本安装

从使用上来说,这个playbook只能安装1.8,而且是写死的,不是简单替换了file文件就行,还需要修改几个参数,如果用上vars,想安装哪个版本就安装哪个版本,相信会更有趣,那么就现在来做吧。
从上面的配置文件中,发现只需要两个地方设置变量即可:

  • unarchive模块的src
  • file模块的src

思路是设置一个初始变量,根据变量的值,来引入不同的变量文件,不同的变量文件中给这两个路径赋值。
而这个初始变量先设定一个默认值,也可以通过 ansible-playbook xxx.yml --extra-vars "变量="来赋值,这样即可设定不同的版本进行部署。
但是这样设置有缺点,那就是根本没有用到roles的vars模块,我想肯定会有更好的方案只是我现在还不知道。
不过我们还是先将目前能想到的解决办法写下来。

4.1 准备文件

把10、11、12各准备一份。

tree files/
files/
├── jdk-10.0.2_linux-x64_bin.tar.gz
├── jdk-11.0.2_linux-x64_bin.tar.gz
├── jdk-12_linux-x64_bin.tar.gz
└── jdk-8u202-linux-x64.tar.gz

0 directories, 4 files

4.2 准备变量文件

其实放置在这个文件夹,到时候也是用绝对地址来引用,所以放在什么地方都可以,不影响。
main.yml文件无配置。

tree vars/
vars/
├── 10.yml
├── 11.yml
├── 12.yml
├── 1.8.yml
└── main.yml

0 directories, 5 files

各个文件的配置:

cat 1.8.yml 
---
jdk_archive: jdk-8u202-linux-x64.tar.gz
jdk_path: /usr/local/bin/jdk1.8.0_202
cat 10.yml 
---
jdk_archive: jdk-10.0.2_linux-x64_bin.tar.gz
jdk_path: /usr/local/bin/jdk-10.0.2
cat 11.yml 
---
jdk_archive: jdk-11.0.2_linux-x64_bin.tar.gz
jdk_path: /usr/local/bin/jdk-11.0.2
cat 12.yml 
---
jdk_archive: jdk-12_linux-x64_bin.tar.gz
jdk_path: /usr/local/bin/jdk-12

4.3 修改tasks文件

仅需修改3个文件,其中tasks文件两个:
path/install_jdk/tasks/unarchive_jdk.yml

---
- name: unarchive jdk{{ jdk_archive }} files
  unarchive:
    src={{ jdk_archive }}
    dest=/usr/local/bin

path/install_jdk/tasks/create_link.yml

---
- name: create link
  file:
    src={{ jdk_path }}
    dest=/usr/local/java
    state=link

但是因为刚刚提到的non-login与login的环境变量不同,所以我们将path写入/etc/bashrc更为稳妥:
path/install_jdk/tasks/config_profile.yml

---
- name: add java path to profile
  lineinfile: 
    path=/etc/bashrc
    line="{{ item }}"
  with_items:
    - export JAVA_HOME=/usr/local/java
    - export JRE_HOME=/usr/local/java/jre
    - export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
    - export PATH=$JAVA_HOME/bin:$PATH
- name: take effect
  shell: source /etc/bashrc

最后是调用文件
ansible/workflow/install_jdk.yml

---
- hosts: node01
  remote_user: root
  vars:
    - version: 1.8
  vars_files:
    - /etc/ansible/roles/install_jdk/vars/{{ version }}.yml

  roles:
    - install_jdk

默认设置为1.8版本,如果需要10、11或12,只需要如下操作:

ansible-playbook install_jdk.yml --extra-vars 'version=11'

执行完毕后查看java版本

ansible node01 -a 'java -version'
node01 | CHANGED | rc=0 >>
java version "11.0.2" 2019-01-15 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.2+9-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.2+9-LTS, mixed mode)

更改为jdk12版本:

ansible-playbook install_jdk.yml --extra-vars 'version=12'

确认版本:

ansible node01 -a 'java -version'
node01 | CHANGED | rc=0 >>
java version "12" 2019-03-19
Java(TM) SE Runtime Environment (build 12+33)
Java HotSpot(TM) 64-Bit Server VM (build 12+33, mixed mode, sharing)

那么一个简陋的多版本JDK部署Roles文件就编写好了。

Last modification:July 27th, 2019 at 12:02 am