乐趣区

关于linux:RFO-SIGopenEuler-AWS-AMI-制作详解

作者简介

王瀚兴,SUSE 软件工程师,次要负责 Rancher 产品线相干的研发工作。

欧拉开源社区的 RFO SIG 正在致力将 openEuler 与 Rancher 整合,以推动社区的云原生幅员倒退。而 openEuler 如何在云环境开箱即用是一个十分重要的根底,承接上篇文章,本篇将次要介绍 openEuler AWS AMI 镜像制作的具体过程。

通过创立 AWS AMI 镜像可将 openEuler 与 AWS 云服务相结合,反对云环境中规范的 ssh key 注入、分区扩容、用户数据执行等性能,并应用 cloud-init 机制实现主动启动 Rancher RKE2 集群。今后,openEuler Cloud Images 的工作也将成为 RFO SIG 的一部分,逐渐扩大反对更多的云平台。

调整硬盘分区大小

openEuler 官网提供的 qcow2 格局的镜像为一个总磁盘大小为 40G 的虚拟机镜像,在 qemu 中启动虚拟机,查看分区状况。

能够看到磁盘含有两个分区,其中 2G 为 boot 分区,38G 为 root 分区。

应用 Net Based Disk (NBD) 将 qcow2 镜像的分区加载到 Linux 零碎中,之后应用 resize2fs 压缩 ext4 文件系统的体积,并应用分区调整工具 fdisk 调整分区的大小。

# 加载 NBD 内核模块
$ sudo modprobe nbd max_part=3
# 加载 qcow2 镜像中的分区至零碎
sudo qemu-nbd -c "/dev/nbd0" "openEuler-22.03-LTS-x86_64.qcow2"
$ lsblk
NAME         MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
nbd0          43:0    0   40G  0 disk
|-nbd0p1      43:1    0    2G  0 part
|-nbd0p2      43:2    0   38G  0 part

# 调整 ext4 文件系统大小至 6G
$ sudo resize2fs /dev/nbd0p2 6G
# 应用 fdisk 调整分区大小至 6G
$ sudo fdisk /dev/nbd0

Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): d
Partition number (1,2, default 2): 2

Partition 2 has been deleted.

Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (2-4, default 2): 2
First sector (4194304-83886079, default 4194304):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4194304-83886079, default 83886079): +6G

Created a new partition 2 of type 'Linux' and of size 6 GiB.
Partition 2 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: N

Command (m for help): w

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

# 从零碎中卸载 qcow2 镜像的分区
$ sudo qemu-nbd -d /dev/nbd0

之后应用 qemu-img 将 qcow2 镜像放大至 8G,并转换为 RAW 格局。

$ qemu-img resize openEuler-22.03-LTS-x86_64.qcow2 --shrink 8G
$ qemu-img convert openEuler-22.03-LTS-x86_64.qcow2 openEuler-22.03-LTS-x86_64.raw

Snapshot 和 Base AMI 的创立

首先应用 awscli 提供的工具,将 RAW 镜像上传至 AWS S3 bucket 中。

$ aws s3 cp openEuler-22.03-LTS-x86_64.raw s3://${BUCKET_NAME}/

创立 vmimport policy 和 role policy。

$ cat << EOF > trust-policy.json
{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": {"Service": "vmie.amazonaws.com"},
         "Action": "sts:AssumeRole",
         "Condition": {
            "StringEquals":{"sts:Externalid": "vmimport"}
         }
      }
   ]
}
EOF

$ aws iam create-role --role-name vmimport --assume-role-policy-document file://trust-policy.json

$ cat << EOF > role-policy.json
{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Effect": "Allow",
         "Action": [
            "s3:GetBucketLocation",
            "s3:GetObject",
            "s3:ListBucket"
         ],
         "Resource": ["arn:aws:s3:::${BUCKET_NAME}",
            "arn:aws:s3:::${BUCKET_NAME}/*"
         ]
      },
      {
         "Effect": "Allow",
         "Action": [
            "s3:GetBucketLocation",
            "s3:GetObject",
            "s3:ListBucket",
            "s3:PutObject",
            "s3:GetBucketAcl"
         ],
         "Resource": ["arn:aws:s3:::${BUCKET_NAME}",
            "arn:aws:s3:::${BUCKET_NAME}/*"
         ]
      },
      {
         "Effect": "Allow",
         "Action": [
            "ec2:ModifySnapshotAttribute",
            "ec2:CopySnapshot",
            "ec2:RegisterImage",
            "ec2:Describe*"
         ],
         "Resource": "*"
      }
   ]
}
EOF

$ aws iam put-role-policy --role-name vmimport --policy-name vmimport --policy-document file://role-policy.json

创立 import-snapshot 工作,将存储在 S3 bucket 的 RAW 镜像创立为 Snapshot。

$ aws ec2 import-snapshot \
   --description "openEuler RAW image import task" \
   --disk-container \
   "Format=RAW,UserBucket={S3Bucket=${BUCKET_NAME},S3Key=openEuler-22.03-LTS-x86_64.raw}"

期待几分钟后,通过 import task ID 获取导入胜利后的 Snapshot ID。

$ aws ec2 describe-import-snapshot-tasks \
      --import-task-ids ${IMPORT_TAST_ID}

应用此 Snapshot 创立不含 cloud init 机制的 Base AMI 镜像。

$ aws ec2 register-image \
    --name "DEV-openEuler-22.03-LTS-x86_64-BASE" \
    --description "DEV openEuler image, do not use for production!" \
    --root-device-name /dev/xvda \
    --architecture x86_64 \
    --ena-support \
    --virtualization-type hvm \
    --block-device-mappings \
      DeviceName=/dev/xvda,Ebs={SnapshotId=${SNAPSHOT_ID}}

至此,咱们取得了 Base AMI ID。

应用 Packer 创立蕴含 Cloud init 机制的 AMI 镜像

首先创立 Packer 的配置文件,留神批改配置文件中的 <BASE_AMI_ID> 为刚刚获取的 Base AMI ID。

{
    "variables": {"version": "{{env `OPENEULER_VERSION`}}",
        "build": "{{env `AWS_IMAGE_BUILD_NUMBER`}}",
        "arch": "{{env `OPENEULER_ARCH`}}"
    },
    "builders": [
        {
            "type": "amazon-ebs",
            "name": "amazon-ebs-hvm-x86_64",
            "region": "ap-northeast-1",
            "ami_regions": ["ap-northeast-1"],
            "source_ami": "<BASE_AMI_ID>",
            "instance_type": "t3a.micro",
            "ssh_username": "root",
            "ssh_password": "openEuler12#$",
            "ami_name": "openEuler-{{user `version`}}-x86_64-hvm-{{user `build`}}",
            "ena_support": "true"
        }
    ],
    "provisioners": [
        {
            "type": "shell",
            "environment_vars": ["VERSION={{user `version`}}",
                "ARCH={{user `arch`}}"
            ],
            "script": "./install-cloudinit.sh"
        }
    ]
}

新建脚本文件 install-cloudinit.sh,用来执行装置 cloud init 和其余配置的指令。

#!/bin/bash
set -e

yum -y update
yum -y install cloud-init cloud-utils-growpart gdisk
yum -y install vim tar make zip gzip wget git tmux \
    conntrack-tools socat iptables-services htop

# disable Apparmor
echo "GRUB_CMDLINE_LINUX_DEFAULT=\"apparmor=0\"" >> /etc/default/grub
# Update grub config
if [["$(uname -m)" == "x86_64" ]]; then
    grub2-mkconfig -o /boot/grub2/grub.cfg
elif [["$(uname -m)" == "arm64" ]]; then
    grub2-mkconfig -o /boot/efi/EFI/openEuler/grub.cfg
fi

最初应用以下指令应用 packer 构建 AMI 镜像。

$ packer build <PACKER_CONFIG.json>

构建 ARM 架构的 AMI 镜像

实践上构建 ARM 架构的 AMI 镜像的整体流程与 x86_64 架构的流程简直统一,然而在实际操作过程中遇到了应用 Base AMI 镜像启动服务器后找不到网卡设施而无奈 ssh 连贯到服务器的状况。

在应用串口连贯到服务器上进行调试后发现,ARM 架构的 openEuler 零碎的内核中没有预装 AWS ENA 网卡驱动,所以无法访问网络连接。

后续 openEuler 会为 ARM 架构的内核削减 ENA 驱动反对,在此之前可应用编译 ENA 驱动内核模块并导入的形式,作为一个长期的解决办法,感兴趣的敌人能够参考一下。

此方法只能作为一个长期的解决办法,不倡议用作生产环境中。

首先在本地运行一个用来编译内核模块的 openEuler aarch64 虚拟机,装置 gcc,make,git,vim 内核头文件等编译须要的工具,克隆 ENA 驱动的源码到本地并编译。

$ yum -y install make git gcc vim kernel-devel-$(uname -r)
$ git clone git clone https://github.com/amzn/amzn-drivers.git
$ cd amzn-drivers/kernel/linux/ena/
$ make -j2

编写这篇文章时,在编译的过程中会遇到这个报错:

/root/amzn-drivers/kernel/linux/ena/ena_ethtool.c:1218:19: error: initialization of‘int (*)(struct net_device *, struct ethtool_coalesce *, struct kernel_ethtool_coalesce *, struct netlink_ext_ack *)’from incompatible pointer type‘int (*)(struct net_device *, struct ethtool_coalesce *)’[-Werror=incompatible-pointer-types]
 1218 |  .get_coalesce  = ena_get_coalesce,
      |                   ^~~~~~~~~~~~~~~~
compilation terminated due to -Wfatal-errors.

一个比拟间接的解决办法是编辑 ena_ethtool.c,在 1218-1221 行,为这几个函数指针增加 (void*) 强制的指针类型转换。

编译后会生成 ena.ko 内核模块文件,可用 modinfo ena.ko 查看该模块的信息。

$ modinfo ena.ko
filename:       /root/amzn-drivers/kernel/linux/ena/ena.ko
version:        2.8.0g
license:        GPL
description:    Elastic Network Adapter (ENA)
author:         Amazon.com, Inc. or its affiliates
......

在调整硬盘分区时,挂载分区,复制此内核模块文件到挂载的分区的目录中并编辑 modprobe 配置文件,在每次开机启动时都加载这个内核模块。

# 假如将分区挂载到了 /mnt 目录上面
$ sudo mount /dev/nbd0p2 /mnt
# 这里将内核模块复制到了 /root 目录上面
$ sudo cp ./ena.ko /mnt/root/
$ sudo bash -c 'echo"install ena insmod /root/ena.ko">> /mnt/etc/modprobe.d/ena.conf'
$ sudo bash -c 'echo"ena">> mnt/etc/modules-load.d/ena.conf'
$ sudo sync && sudo umount /mnt

重启零碎后,能够应用 lsmod 查看已加载的内核模块,或应用 dmesg 查看内核日志,能够看到 ENA 驱动被加载的记录。

$ sudo lsmod
Module                  Size  Used by
ena                   147456  0
......

$ dmesg | grep ena:
[94.814488] ena: loading out-of-tree module taints kernel.
[94.814896] ena: module verification failed: signature and/or required key missing - tainting kernel

目前 openEuler 社区已修复了 ARM 架构的内核不蕴含 ENA 网卡驱动的问题,会在后续的内核更新中获取到蕴含 ENA 驱动的内核。更多信息可在此 PR 中获取到:https://gitee.com/openeuler/k…

已构建的 AMI 镜像应用

在 AWS EC2 实例的控制台页面,应用构建的 AMI 镜像创立一个 EC2 虚拟机,设定网络安全组、SSH 密钥、磁盘大小、用户数据等配置。

在本篇文章中,设定的 EBS 磁盘大小为 30G,在用户数据中填写了装置 RKE2 的脚本:

#!/bin/bash

echo "-------- Start custom user data ----------"

yum update
curl -sfL https://get.rke2.io > install.sh
chmod +x ./install.sh
sudo INSTALL_RKE2_METHOD=tar ./install.sh
sudo systemctl enable rke2-server
sudo systemctl start rke2-server

echo "-------- User data finished successfully -----------"

实例启动后,cloud init 机制会主动创立用户名为 openeuler 的账号并设定仅应用 ssh key 登录,同时 root 账号的 ssh 登录也会被禁止。磁盘的 root 分区会主动扩容到咱们设定的 EBS 磁盘大小,用户数据中填写的脚本也将被主动执行。

查看 cloud init 输入的日志,其中包含用户数据的执行后果:

$ tail -f /var/log/cloud-init-output.log
Is this ok [y/N]: Operation aborted.
[INFO]  finding release for channel stable
[INFO]  using v1.24.4+rke2r1 as release
[INFO]  downloading checksums at https://github.com/rancher/rke2/releases/download/v1.24.4+rke2r1/sha256sum-amd64.txt
[INFO]  downloading tarball at https://github.com/rancher/rke2/releases/download/v1.24.4+rke2r1/rke2.linux-amd64.tar.gz
[INFO]  verifying tarball
[INFO]  unpacking tarball file to /usr/local
Created symlink /etc/systemd/system/multi-user.target.wants/rke2-server.service → /usr/local/lib/systemd/system/rke2-server.service.
-------- User data finished successfully -----------
Cloud-init v. 21.4 finished at Wed, 21 Sep 2022 06:56:30 +0000. Datasource DataSourceEc2Local.  Up 130.47 seconds

验证分区主动扩容至总容量为设定的 EBS 的大小:

$ lsblk
NAME        MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1     259:0    0  30G  0 disk
├─nvme0n1p1 259:1    0   2G  0 part /boot
└─nvme0n1p2 259:2    0  28G  0 part /

验证 RKE2 装置胜利,所有 pods 均失常启动:

$ sudo /var/lib/rancher/rke2/bin/kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml get nodes
NAME                                               STATUS   ROLES                       AGE     VERSION
ip-172-31-21-213.ap-northeast-1.compute.internal   Ready    control-plane,etcd,master   7m58s   v1.24.4+rke2r1

$ sudo /var/lib/rancher/rke2/bin/kubectl --kubeconfig /etc/rancher/rke2/rke2.yaml get pods -A
NAMESPACE     NAME                                                                        READY   STATUS      RESTARTS   AGE
kube-system   cloud-controller-manager-ip-172-31-21-213.ap-northeast-1.compute.internal   1/1     Running     0          14m
kube-system   etcd-ip-172-31-21-213.ap-northeast-1.compute.internal                       1/1     Running     0          14m
kube-system   helm-install-rke2-canal-l5rnl                                               0/1     Completed   0          14m
kube-system   helm-install-rke2-coredns-jckq7                                             0/1     Completed   0          14m
kube-system   helm-install-rke2-ingress-nginx-dxcsc                                       0/1     Completed   0          14m
kube-system   helm-install-rke2-metrics-server-kgjdf                                      0/1     Completed   0          14m
kube-system   kube-apiserver-ip-172-31-21-213.ap-northeast-1.compute.internal             1/1     Running     0          14m
kube-system   kube-controller-manager-ip-172-31-21-213.ap-northeast-1.compute.internal    1/1     Running     0          14m
kube-system   kube-proxy-ip-172-31-21-213.ap-northeast-1.compute.internal                 1/1     Running     0          14m
kube-system   kube-scheduler-ip-172-31-21-213.ap-northeast-1.compute.internal             1/1     Running     0          14m
kube-system   rke2-canal-ng2sw                                                            2/2     Running     0          13m
kube-system   rke2-coredns-rke2-coredns-76cb76d66-nklrw                                   1/1     Running     0          13m
kube-system   rke2-coredns-rke2-coredns-autoscaler-58867f8fc5-mpgd7                       1/1     Running     0          13m
kube-system   rke2-ingress-nginx-controller-fhpbd                                         1/1     Running     0          12m
kube-system   rke2-metrics-server-6979d95f95-2lrp8                                        1/1     Running     0          13m

About SUSE Rancher

Rancher 是一个开源的企业级 Kubernetes 治理平台,实现了 Kubernetes 集群在混合云 + 本地数据中心的集中部署与治理。Rancher 一贯因操作体验的直观、极简备受用户青眼,被 Forrester 评为“2020 年多云容器开发平台领导厂商”以及“2018 年寰球容器治理平台领导厂商”,被 Gartner 评为“2017 年寰球最酷的云基础设施供应商”。

目前 Rancher 在寰球领有超过三亿的外围镜像下载量,并领有包含中国联通、中国安全、中国人寿、上汽团体、三星、施耐德电气、西门子、育碧游戏、LINE、WWK 保险团体、澳电讯公司、德国铁路、厦门航空、新东方等寰球驰名企业在内的共 40000 家企业客户。

2020 年 12 月,SUSE 实现收买 RancherLabs,Rancher 成为了 SUSE“翻新无处不在(Innovate Everywhere)”企业愿景的要害组成部分。SUSE 和 Rancher 独特为客户提供了无可比拟的自在和所向无敌的创新能力,通过混合云 IT 基础架构、云原生转型和 IT 运维解决方案,简化、现代化并减速企业数字化转型,推动翻新无处不在。

以后,SUSE 及 Rancher 在中国大陆及港澳台地区的业务,均由数硕软件(北京)有限公司承载。SUSE 在国内领有优良的研发团队、技术支持团队和销售团队,将联合 Rancher 当先的云原生技术,为中国的企业客户提供更加及时和可信赖的技术撑持及服务保障。

退出移动版