分类 Coding 下的文章

什么是 Docker

Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,它是基于 dotCloud 公司多年云服务技术的一次革新
Docker 使用 Google 公司推出的 Go 语言 进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于 操作系统层面的虚拟化技术。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

docker-on-linux.png

什么是 Docker 仓库

仓库(Repository)是集中存放镜像的地方。
一个容易混淆的概念是注册服务器(Registry)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 docker.io/ubuntu 来说,docker.io 是注册服务器地址,ubuntu 是仓库名。
大部分时候,并不需要严格区分这两者的概念。

什么是 Docker 私有仓库(Registry)

一般情况下,我们可以通过Docker Hub在整个网络中下载或者分享Docker镜像。同时相比Docker Hub这样的公共仓库,用户可以创建私有仓库供私人使用。

官方提供了docker-registryDocker镜像用于构建私有的镜像仓库。目前是 v2.x 版本。

搭建Docker私有仓库的步骤

一般需要以下几个大致的步骤:

  1. 从Docker Hub拉取docker-registry镜像
  2. 创建docker-registry配置文件,并启动docker-registry
  3. 通过nginxdocker-registry发布到互联网。(内部使用可忽略此步骤)

搭建 Docker 私有仓库Web管理平台

使用docker-compose一次性完成所有搭建

参考

  1. Docker私有仓库搭建与界面化管理
  2. 私有仓库

Managed Package有许多限制,比如无法在外部/本地代码中序列化受控包中的Apex Class

JSON Support Considerations

Only custom objects, which are sObject types, of managed packages can be serialized from code that is external to the managed package. Objects that are instances of Apex classes defined in the managed package can't be serialized.

假如有个包Px,命名空间Px。我们有个Apex Class需要调用里面的对象并JSON序列化。

直接JSON序列化是不行的

包中代码:

//Inside package Px
global class C {
  global String stringA;
  global Integer StringB;
}

本地代码调用,会失败:

@isTest
private class TestFromLocal {
    @isTest static void testSerialize() {
    try{ 
      JSON.serialize(new Px.C());
      System.assert(false,'This should fail');
    } catch (Exception ex) {
      System.assertEquals('Cannot serialize type from package: Px.C',ex.getMessage());
    }
  }
}

但是可以通过扩展Apex Class来序列化

我们可以利用扩展(extends)一个虚拟类(virtual class)来实现序列化!

1. 保证需要序列化的Class是virtual

包中代码:

//Inside package Px
global virtual class C {
  global String stringA;
  global Integer StringB;
}

2. extends it!

@isTest
private class TestFromLocal {

class Ext extends Px.C { }

@isTest static void testSerialize() {
  Ext virt = new Ext();
  virt.stringA = 'bla';
  virt.IntgerB = 1;
  System.assertEquals('{"stringA":"bla", "IntgerB": 1}',JSON.serialize(virt));
}

}

这样就可以正常调用了!

参考

1.Salesforce: Serializing Objects from a Managed Package

软件测试是一个工程

属于软件质量控制、质量保证的一部分。由于软件的复杂性,软件测试需要分出层次来,并由不同的人完成不同的测试任务,在不同层面不同维度和角度保证软件按照设计和预期运行。

软件测试并不是银弹,不能保证软件100%没有问题。但是组织良好的软件测试工程,相比随意和混乱的测试甚至不测试,能够以比较低的成本发现大部分的软件缺陷,保证软件质量。

软件测试按照不同的层级,分为:单元测试, 系统(功能)测试, UAT测试, 生产测试, 回归测试

单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。这部分测试过程由负责开发相应软件模块单元的开发人员执行,一般软件都会要求在源代码层面,单元测试能够测试(覆盖)到大部分的软件源代码。比如Salesforce要求部署到生产环境的代码必须有75%的代码覆盖率。

系统(功能)测试

一般会把功能测试和系统测试分开,但是实际上这些测试过程都由软件测试工程师执行。功能测试偏向每个功能运行的正确和准确,是从细节的角度解读测试;而系统测试则偏向整个软件系统的整体运行,包含一些非功能性测试(例如响应时间、安全等),是从整体的角度解读测试。但是不论功能测试或者系统测试,都是从逻辑的层面确保软件的每个功能和整个软件系统的正常运行。

UAT测试

UAT测试,即用户认可测试,必须由将使用软件的最终用户进行。测试将模拟业务中的实际事件和日常使用情况,因此您可以确认该软件是否满足用户的需求。UAT测试是从业务的层面出发,保障系统的满足实际业务需求。

生产测试

在生产环境中重复进行系统(功能)测试的一部分测试,这将确认代码和配置是否已从测试或沙盒环境正确转移到生产环境中中。建议在此步骤后重复进行 UAT 测试。

回归测试

一旦发布并安装了新的软件更新,或者检测到并修复了错误,都应该进行回归测试。即从头到尾对受升级或者修复错误影响的软件部分从头到位测试一遍(回归)。它确保所有以前的使用和过程在进行更改后仍然正常有效地运行。

可以看到,不同层次和类别的测试,有不同的角度和目的,也由不同的人员执行。让软件开发人员或者最终用户直接完成所有的测试工作,都是不可靠的。因为他们掌握的知识技能和他们的背景以及经验,不足以应对整个复杂的分层次的软件测试工程。

2GP Managed Package

Salesforce 第二代管控包(Second-Generation Managed Packages)是Salesforce最新推广的最佳实践。通过Salesforce CLI,我们可以很方便的制作和部署第二代管控包。本文只是简略的将核心步骤展示出来:

涉及的各种环境

整个第二代管控包需要用到4类org:

  1. Dev Hub Org:承载所有二代包。可以将各个命名空间的二代包链接到这个org。最好是PBO
  2. Namespace Org:一般是Developer org,在其中申请相应的命名空间,由于命名空间一旦申请便与该org永久绑定且不可修改,申请时请慎重。
  3. Scratch Orgs:在开发测试中使用。
  4. Production Orgs:按照和使用包的生产环境。

2GP Packages.drawio.svg
相关org关系示意图。

10步完成制作

  1. 创建一个 SFDX 项目

    sfdx force:project:create --outputdir expense-manager-workspace --projectname expenser-app
  2. 授权Dev Hub环境,该环境必须启用Dev Hub功能和未锁定包和第二代管控包功能

    sfdx auth:web:login -d -a devHub
  3. 创建一个草稿环境(scratch org)并在其中开发包

    sfdx force:org:create -f config/project-scratch-def.json -u scratchOrg1
  4. 保证所有要打包的组件都已经在当前的项目文件夹内
  5. sfdx-project.json文件中,使用命名空间属性指定命名空间。例如:“namespace”:“exp-mgr”
  6. 从 SFDX 项目文件夹,直接创建管控包:

    sfdx force:package:create --name "Expense Manager" --path force-app --packagetype Managed
  7. 检查项目文件夹中的sfdx-project.json文件,CLI 会自动更新项目文件,使其包含上一步创建的包的信息:

    {
    "packageDirectories": [
       {
          "path": "force-app",
          "default": true,
          "package": "Expense Manager",
          "versionName": "ver 0.1",
          "versionNumber": "0.1.0.NEXT"
       }
    ],
    "namespace": "exp-mgr",
    "sfdcLoginUrl": "https://login.salesforce.com",
    "sourceApiVersion": "51.0",
    "packageAliases": {
       "Expense Manager": "0Hoxxx"
    }
    }
  8. 创建一个包的版本,Salesforce CLI会自动处理包的版本号等

    sfdx force:package:version:create --package "Expense Manager" --installationkey test1234 --wait 10
  9. 在另一个创建好的草稿环境中,安装并测试这个版本的包:

    sfdx force:package:install --package "Expense [email protected]" --targetusername MyTestOrg1 
    --installationkey test1234 --wait 10 --publishwait 10
  10. 安装包后,打开scratch org查看包:

    sfdx force:org:open --targetusername MyTestOrg1
\frac{a}{b^2}

参考:

  1. Salesforce DX Developer Guide
  2. Link a Namespace to a Dev Hub Org
  3. Create and Register Your Namespace for Second-Generation Managed Packages
  4. Workflow for Second-Generation Managed Packages

云服务器中通过Docker镜像的方式使用Mysql数据库,数据安全考量定期备份数据库到阿里云OSS中

本文主要实现在阿里云ECS服务器中,通过脚本的方式实现将Docker中的Mysql数据库备份到阿里云OSS中。其他云服务商和其他环境的MySQL也可以使用类似的方式。具体方式不再赘述。

环境和工具

  1. 阿里云ECS服务器,安装Ubuntu或任何带有定时任务cron的Linux操作系统
  2. 阿里云OSS bucket和相应访问的账户
  3. 阿里云OSS命令行工具ossutil,可以到这里下载或查看详情
  4. MySQL镜像

具体步骤

开通OSS和相应子账号

  1. 进入阿里云OSS(对象存储)控制台,如果没有开通OSS服务可能会提示权限和开通确认。
  2. 创建bucket/存储桶,输入名字,比如xxxxbackup,记住这个名字以及界面中出现的Endpoint(地域节点),后续会用到。
    WX20220720-115411.png
  3. 创建一个有API的阿里云子账号,并赋予OSS读写权限。记住该账号的API和Secret,后续会用到。帮助文档
    WX20220720-115547.png

下载OSS命令行工具ossutil到本地系统

  1. 通过wget https://gosspublic.alicdn.com/ossutil/1.7.13/ossutil64下载到本地。这里是64位操作系统,32位可以去下载界面查看对应的下载地址。
  2. 增加运行权限:chmod +x ossutil64
  3. 移动到Path中:sudo mv ossutil64 /bin/

编写脚本

这里需要注意docker容器的名称,容器中应该有MYSQL用户名和密码的环境变量;示例中使用的是root作为用户名;另外备份临时文件夹也需要提前使用mkdir建好

脚本内容示例:

#!/bin/sh 

mysql_dump_path=备份文件临时目录,如/var/dbbackup/ 

#oss-config 
oss_endpoint="阿里云OSS Endpoint" 
oss_bucket="阿里云OSS bucket名称" 
oss_accesskeyid="子账号AccessKeyId" 
oss_accesskeysecret="子账号 AccessKey Secret" 
backup_name=`date +%Y%m%d%H%M%S`
cd ${mysql_dump_path} 

# 使用 mysqldump 备份整个数据库到临时文件夹中
# 注意docker修改docker镜像名称,这里是some-mysql
docker exec some-mysql sh -c 'mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --all-databases' > ${backup_name}.sql

# 打包/pack 
tar zcf ${backup_name}.tar.gz ${backup_name}.sql 
rm -f ${backup_name}.sql 

# 备份到OSS
ossutil64 cp ${backup_name}.tar.gz oss://${oss_bucket}/mysql/backup/${backup_name}.tar.gz -f -e ${oss_endpoint} -i ${oss_accesskeyid} -k ${oss_accesskeysecret} 
rm -f ${backup_name}.tar.gz 
echo "备份完成"

将脚本保存至任意一个不错的位置,比如/var/backup/dbbackup.sh,赋予可执行权限:sudo chmod +x /var/backup/dbbackup.sh

试着运行一下脚本文件sudo /var/backup/dbbackup.sh,再去oss控制台该bucket下-文件管理处查看是否有备份文件存入。如果一切没有问题,则就可以加入cron了。

加入cron计划任务

注:如果脚本位置和临时备份文件夹位置是当前用户无法直接编辑的,则应使用一下方法,在系统级别运行计划任务;用户级别会因为权限问题出错

使用你喜欢的编辑器打开/etc/crontab文件,并在文件末尾加上这行:

23 2 * * * root /var/backup/dbbackup.sh

这表示在每天的02:23:00运行我们的备份脚本。

重新启动cron计划任务:sudo service cron reload

在次日2:23分之后检查OSS控制台后台,即可发现整个数据库已经备份到阿里云OSS。

参考

  1. 使用ossutil定时备份自建mysql数据库到阿里云OSS
  2. Cron介绍
  3. docker hub: mysql