标签归档:continuous-integration

Python的“漂亮”持续集成

问题:Python的“漂亮”持续集成

这是一个..徒劳的问题,但是BuildBot的输出并不是特别好看。

例如,相比

..及其他,BuildBot看起来..古老

我目前正在与Hudson一起玩,但是它是非常以Java为中心的(尽管使用本指南,我发现它比BuildBot容易设置,并提供了更多信息)

基本上:是否有任何针对python的持续集成系统,它们会生成许多闪亮的图形等?


更新:自从这次以来,Jenkins项目已将Hudson替换为软件包的社区版本。原始作者也已移至该项目。Jenkins现在是Ubuntu / Debian,RedHat / Fedora / CentOS等上的标准软件包。以下更新本质上仍然正确。詹金斯做到这一点的起点是不同的。

更新:尝试了几种选择之后,我认为我会坚持使用哈德森。完整性很好而且很简单,但是非常有限。我认为 Buildbot更适合拥有多个构建从属,而不是像我在使用它那样在一台机器上运行的所有东西。

将Hudson设置为Python项目非常简单:

  • http://hudson-ci.org/下载Hudson
  • 运行它 java -jar hudson.war
  • 打开Web界面的默认地址为 http://localhost:8080
  • 转到管理哈德森,插件,单击“更新”或类似内容
  • 安装Git插件(我必须git在Hudson全局首选项中设置路径)
  • 创建一个新项目,输入存储库,SCM轮询间隔等
  • 如果尚未安装,请nosetests通过安装easy_install
  • 在构建步骤中,添加 nosetests --with-xunit --verbose
  • 选中“发布JUnit测试结果报告”并将“测试报告XML”设置为 **/nosetests.xml

这就是全部。您可以设置电子邮件通知,这些插件值得一看。我目前正在使用一些Python项目:

  • SLOCCount插件可以计算代码行(并绘制图形!)-您需要单独安装sloccount
  • 违反解析PyLint输出(您可以设置警告阈值,绘制每个构建中违反次数的图表)
  • Cobertura可以解析coverage.py的输出。Nosetest可以在运行测试时使用收集覆盖范围nosetests --with-coverage(将输出写入**/coverage.xml

This is a slightly.. vain question, but BuildBot’s output isn’t particularly nice to look at..

For example, compared to..

..and others, BuildBot looks rather.. archaic

I’m currently playing with Hudson, but it is very Java-centric (although with this guide, I found it easier to setup than BuildBot, and produced more info)

Basically: is there any Continuous Integration systems aimed at python, that produce lots of shiny graphs and the likes?


Update: Since this time the Jenkins project has replaced Hudson as the community version of the package. The original authors have moved to this project as well. Jenkins is now a standard package on Ubuntu/Debian, RedHat/Fedora/CentOS, and others. The following update is still essentially correct. The starting point to do this with Jenkins is different.

Update: After trying a few alternatives, I think I’ll stick with Hudson. Integrity was nice and simple, but quite limited. I think Buildbot is better suited to having numerous build-slaves, rather than everything running on a single machine like I was using it.

Setting Hudson up for a Python project was pretty simple:

  • Download Hudson from http://hudson-ci.org/
  • Run it with java -jar hudson.war
  • Open the web interface on the default address of http://localhost:8080
  • Go to Manage Hudson, Plugins, click “Update” or similar
  • Install the Git plugin (I had to set the git path in the Hudson global preferences)
  • Create a new project, enter the repository, SCM polling intervals and so on
  • Install nosetests via easy_install if it’s not already
  • In the a build step, add nosetests --with-xunit --verbose
  • Check “Publish JUnit test result report” and set “Test report XMLs” to **/nosetests.xml

That’s all that’s required. You can setup email notifications, and the plugins are worth a look. A few I’m currently using for Python projects:

  • SLOCCount plugin to count lines of code (and graph it!) – you need to install sloccount separately
  • Violations to parse the PyLint output (you can setup warning thresholds, graph the number of violations over each build)
  • Cobertura can parse the coverage.py output. Nosetest can gather coverage while running your tests, using nosetests --with-coverage (this writes the output to **/coverage.xml)

回答 0

您可能想看看NoseXunit输出插件。您可以使用以下命令运行单元测试和覆盖率检查:

nosetests --with-xunit --enable-cover

如果您想走Jenkins路线,或者要使用其他支持JUnit测试报告的CI服务器,这将很有帮助。

同样,您可以使用Jenkins违规插件捕获pylint的输出

You might want to check out Nose and the Xunit output plugin. You can have it run your unit tests, and coverage checks with this command:

nosetests --with-xunit --enable-cover

That’ll be helpful if you want to go the Jenkins route, or if you want to use another CI server that has support for JUnit test reporting.

Similarly you can capture the output of pylint using the violations plugin for Jenkins


回答 1

不知道它是否会做:Bitten是由写Trac的人制作的,并与Trac集成在一起。Apache Gump是Apache使用的CI工具。它是用Python编写的。

Don’t know if it would do : Bitten is made by the guys who write Trac and is integrated with Trac. Apache Gump is the CI tool used by Apache. It is written in Python.


回答 2

使用TeamCity作为CI服务器并使用鼻子作为测试运行器,我们已经取得了巨大的成功。 Teamcity的鼻子测试插件可让您计数通过/失败,失败的测试的可读显示(可以通过电子邮件发送)。您甚至可以在堆栈运行时查看测试失败的详细信息。

当然,如果支持在多台计算机上运行之类的事情,则它的设置和维护比buildbot容易得多。

We’ve had great success with TeamCity as our CI server and using nose as our test runner. Teamcity plugin for nosetests gives you count pass/fail, readable display for failed test( that can be E-Mailed). You can even see details of the test failures while you stack is running.

If of course supports things like running on multiple machines, and it’s much simpler to setup and maintain than buildbot.


回答 3

Buildbot的瀑布页面可以修饰得很漂亮。这是一个很好的例子http://build.chromium.org/buildbot/waterfall/waterfall

Buildbot’s waterfall page can be considerably prettified. Here’s a nice example http://build.chromium.org/buildbot/waterfall/waterfall


回答 4

Atlassian的Bamboo也绝对值得一试。整个Atlassian套件(JIRA,Confluence,FishEye等)非常漂亮。

Atlassian’s Bamboo is also definitely worth checking out. The entire Atlassian suite (JIRA, Confluence, FishEye, etc) is pretty sweet.


回答 5

我猜这个线程已经很老了,但是这是我和哈德森的看法:

我决定与pip一起建立一个repo(上班很痛苦,但是看上去很漂亮),hudson会自动将其上传到测试成功的仓库中。这是与hudson config执行脚本一起使用的我粗略且准备就绪的脚本,例如:/var/lib/hudson/venv/main/bin/hudson_script.py -w $ WORKSPACE -p my.package -v $ BUILD_NUMBER,只需放入** / coverage.xml,pylint.txt和鼻子测试.xml在配置位中:

#!/var/lib/hudson/venv/main/bin/python
import os
import re
import subprocess
import logging
import optparse

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(levelname)s %(message)s')

#venvDir = "/var/lib/hudson/venv/main/bin/"

UPLOAD_REPO = "http://ldndev01:3442"

def call_command(command, cwd, ignore_error_code=False):
    try:
        logging.info("Running: %s" % command)
        status = subprocess.call(command, cwd=cwd, shell=True)
        if not ignore_error_code and status != 0:
            raise Exception("Last command failed")

        return status

    except:
        logging.exception("Could not run command %s" % command)
        raise

def main():
    usage = "usage: %prog [options]"
    parser = optparse.OptionParser(usage)
    parser.add_option("-w", "--workspace", dest="workspace",
                      help="workspace folder for the job")
    parser.add_option("-p", "--package", dest="package",
                      help="the package name i.e., back_office.reconciler")
    parser.add_option("-v", "--build_number", dest="build_number",
                      help="the build number, which will get put at the end of the package version")
    options, args = parser.parse_args()

    if not options.workspace or not options.package:
        raise Exception("Need both args, do --help for info")

    venvDir = options.package + "_venv/"

    #find out if venv is there
    if not os.path.exists(venvDir):
        #make it
        call_command("virtualenv %s --no-site-packages" % venvDir,
                     options.workspace)

    #install the venv/make sure its there plus install the local package
    call_command("%sbin/pip install -e ./ --extra-index %s" % (venvDir, UPLOAD_REPO),
                 options.workspace)

    #make sure pylint, nose and coverage are installed
    call_command("%sbin/pip install nose pylint coverage epydoc" % venvDir,
                 options.workspace)

    #make sure we have an __init__.py
    #this shouldn't be needed if the packages are set up correctly
    #modules = options.package.split(".")
    #if len(modules) > 1: 
    #    call_command("touch '%s/__init__.py'" % modules[0], 
    #                 options.workspace)
    #do the nosetests
    test_status = call_command("%sbin/nosetests %s --with-xunit --with-coverage --cover-package %s --cover-erase" % (venvDir,
                                                                                     options.package.replace(".", "/"),
                                                                                     options.package),
                 options.workspace, True)
    #produce coverage report -i for ignore weird missing file errors
    call_command("%sbin/coverage xml -i" % venvDir,
                 options.workspace)
    #move it so that the code coverage plugin can find it
    call_command("mv coverage.xml %s" % (options.package.replace(".", "/")),
                 options.workspace)
    #run pylint
    call_command("%sbin/pylint --rcfile ~/pylint.rc -f parseable %s > pylint.txt" % (venvDir, 
                                                                                     options.package),
                 options.workspace, True)

    #remove old dists so we only have the newest at the end
    call_command("rm -rfv %s" % (options.workspace + "/dist"),
                 options.workspace)

    #if the build passes upload the result to the egg_basket
    if test_status == 0:
        logging.info("Success - uploading egg")
        upload_bit = "upload -r %s/upload" % UPLOAD_REPO
    else:
        logging.info("Failure - not uploading egg")
        upload_bit = ""

    #create egg
    call_command("%sbin/python setup.py egg_info --tag-build=.0.%s --tag-svn-revision --tag-date sdist %s" % (venvDir,
                                                                                                              options.build_number,
                                                                                                              upload_bit),
                 options.workspace)

    call_command("%sbin/epydoc --html --graph all %s" % (venvDir, options.package),
                 options.workspace)

    logging.info("Complete")

if __name__ == "__main__":
    main()

在部署内容时,您可以执行以下操作:

pip -E /location/of/my/venv/ install my_package==X.Y.Z --extra-index http://my_repo

然后人们可以使用以下方法开发东西:

pip -E /location/of/my/venv/ install -e ./ --extra-index http://my_repo

这些东西假设您每个包都有一个带有setup.py和依赖项的仓库结构,然后就可以检出中继并在上面运行它。

我希望这可以帮助某人。

——更新———

我添加了epydoc,它非常适合hudson。只需使用html文件夹将javadoc添加到您的配置中

请注意,pip目前不正确支持-E标志,因此您必须单独创建venv

I guess this thread is quite old but here is my take on it with hudson:

I decided to go with pip and set up a repo (the painful to get working but nice looking eggbasket), which hudson auto uploads to with a successful tests. Here is my rough and ready script for use with a hudson config execute script like: /var/lib/hudson/venv/main/bin/hudson_script.py -w $WORKSPACE -p my.package -v $BUILD_NUMBER, just put in **/coverage.xml, pylint.txt and nosetests.xml in the config bits:

#!/var/lib/hudson/venv/main/bin/python
import os
import re
import subprocess
import logging
import optparse

logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s %(levelname)s %(message)s')

#venvDir = "/var/lib/hudson/venv/main/bin/"

UPLOAD_REPO = "http://ldndev01:3442"

def call_command(command, cwd, ignore_error_code=False):
    try:
        logging.info("Running: %s" % command)
        status = subprocess.call(command, cwd=cwd, shell=True)
        if not ignore_error_code and status != 0:
            raise Exception("Last command failed")

        return status

    except:
        logging.exception("Could not run command %s" % command)
        raise

def main():
    usage = "usage: %prog [options]"
    parser = optparse.OptionParser(usage)
    parser.add_option("-w", "--workspace", dest="workspace",
                      help="workspace folder for the job")
    parser.add_option("-p", "--package", dest="package",
                      help="the package name i.e., back_office.reconciler")
    parser.add_option("-v", "--build_number", dest="build_number",
                      help="the build number, which will get put at the end of the package version")
    options, args = parser.parse_args()

    if not options.workspace or not options.package:
        raise Exception("Need both args, do --help for info")

    venvDir = options.package + "_venv/"

    #find out if venv is there
    if not os.path.exists(venvDir):
        #make it
        call_command("virtualenv %s --no-site-packages" % venvDir,
                     options.workspace)

    #install the venv/make sure its there plus install the local package
    call_command("%sbin/pip install -e ./ --extra-index %s" % (venvDir, UPLOAD_REPO),
                 options.workspace)

    #make sure pylint, nose and coverage are installed
    call_command("%sbin/pip install nose pylint coverage epydoc" % venvDir,
                 options.workspace)

    #make sure we have an __init__.py
    #this shouldn't be needed if the packages are set up correctly
    #modules = options.package.split(".")
    #if len(modules) > 1: 
    #    call_command("touch '%s/__init__.py'" % modules[0], 
    #                 options.workspace)
    #do the nosetests
    test_status = call_command("%sbin/nosetests %s --with-xunit --with-coverage --cover-package %s --cover-erase" % (venvDir,
                                                                                     options.package.replace(".", "/"),
                                                                                     options.package),
                 options.workspace, True)
    #produce coverage report -i for ignore weird missing file errors
    call_command("%sbin/coverage xml -i" % venvDir,
                 options.workspace)
    #move it so that the code coverage plugin can find it
    call_command("mv coverage.xml %s" % (options.package.replace(".", "/")),
                 options.workspace)
    #run pylint
    call_command("%sbin/pylint --rcfile ~/pylint.rc -f parseable %s > pylint.txt" % (venvDir, 
                                                                                     options.package),
                 options.workspace, True)

    #remove old dists so we only have the newest at the end
    call_command("rm -rfv %s" % (options.workspace + "/dist"),
                 options.workspace)

    #if the build passes upload the result to the egg_basket
    if test_status == 0:
        logging.info("Success - uploading egg")
        upload_bit = "upload -r %s/upload" % UPLOAD_REPO
    else:
        logging.info("Failure - not uploading egg")
        upload_bit = ""

    #create egg
    call_command("%sbin/python setup.py egg_info --tag-build=.0.%s --tag-svn-revision --tag-date sdist %s" % (venvDir,
                                                                                                              options.build_number,
                                                                                                              upload_bit),
                 options.workspace)

    call_command("%sbin/epydoc --html --graph all %s" % (venvDir, options.package),
                 options.workspace)

    logging.info("Complete")

if __name__ == "__main__":
    main()

When it comes to deploying stuff you can do something like:

pip -E /location/of/my/venv/ install my_package==X.Y.Z --extra-index http://my_repo

And then people can develop stuff using:

pip -E /location/of/my/venv/ install -e ./ --extra-index http://my_repo

This stuff assumes you have a repo structure per package with a setup.py and dependencies all set up then you can just check out the trunk and run this stuff on it.

I hope this helps someone out.

——update———

I’ve added epydoc which fits in really nicely with hudson. Just add javadoc to your config with the html folder

Note that pip doesn’t support the -E flag properly these days, so you have to create your venv separately


回答 6

另一个:Shining Panda是python的托管工具

another one : Shining Panda is a hosted tool for python


回答 7

如果您正在考虑托管CI解决方案并进行开源,那么您也应该研究Travis CI-它与GitHub的集成非常好。当它最初是Ruby工具时,他们不久前就添加了Python支持

If you’re considering hosted CI solution, and doing open source, you should look into Travis CI as well – it has very nice integration with GitHub. While it started as a Ruby tool, they have added Python support a while ago.


回答 8

信号是另一种选择。您可以在此处了解更多信息并观看视频。

Signal is another option. You can know more about it and watch a video also here.


回答 9

我会考虑使用CircleCi-它具有强大的Python支持,并且输出非常漂亮。

I would consider CircleCi – it has great Python support, and very pretty output.


回答 10

Continuousumbinstar现在可以触发来自github的构建,并且可以针对linux,osx和Windows(32/64)进行编译。整洁的是,它确实允许您紧密耦合分发和持续集成。这是跨越t并整合I的点。该站点,工作流和工具确实经过了完善,并且AFAIK conda是分发复杂的python模块的最可靠,最pythonic的方式,您需要在其中包装分发C / C ++ / Fotran库。

continuum’s binstar now is able to trigger builds from github and can compile for linux, osx and windows ( 32 / 64 ). the neat thing is that it really allows you to closely couple distribution and continuous integration. That’s crossing the t’s and dotting the I’s of Integration. The site, workflow and tools are really polished and AFAIK conda is the most robust and pythonic way to distributing complex python modules, where you need to wrap and distribute C/C++/Fotran libraries.


回答 11

我们已经使用过很多咬了。它很漂亮,并且可以与Trac很好地集成在一起,但是如果您有任何非标准的工作流程,则很难自定义。而且,与流行工具相比,插件的数量也不多。目前,我们正在评估哈德森作为替代者。

We have used bitten quite a bit. It is pretty and integrates well with Trac, but it is a pain in the butt to customize if you have any nonstandard workflow. Also there just aren’t as many plugins as there are for the more popular tools. Currently we are evaluating Hudson as a replacement.


回答 12

检查rultor.com。如本文所述,它在每个构建中都使用Docker。因此,您可以在Docker映像中配置任何所需的内容,包括Python。

Check rultor.com. As this article explains, it uses Docker for every build. Thanks to that, you can configure whatever you like inside your Docker image, including Python.


回答 13

小小免责声明,我实际上已经为客户端构建了这样的解决方案,该客户端想要一种方法来自动测试和部署git push上的任何代码,以及通过git notes管理问题单。这也导致我从事AIMS项目

人们很容易只安装,通过有一个内置的用户和管理他们构建裸节点系统make(1)expect(1)crontab(1)/ systemd.unit(5),和incrontab(1)。甚至可以更进一步,并通过gridfs / nfs文件存储将ansible和celery用于分布式构建。

虽然,我不希望Graybeard UNIX的人或Principles级的工程师/架构师能走这么远。这只是一个好主意和潜在的学习经验,因为构建服务器无非是一种以自动化方式任意执行脚本任务的方法。

Little disclaimer, I’ve actually had to build a solution like this for a client that wanted a way to automatically test and deploy any code on a git push plus manage the issue tickets via git notes. This also lead to my work on the AIMS project.

One could easily just setup a bare node system that has a build user and manage their build through make(1), expect(1), crontab(1)/systemd.unit(5), and incrontab(1). One could even go a step further and use ansible and celery for distributed builds with a gridfs/nfs file store.

Although, I would not expect anyone other than a Graybeard UNIX guy or Principle level engineer/architect to actually go this far. Just makes for a nice idea and potential learning experience since a build server is nothing more than a way to arbitrarily execute scripted tasks in an automated fashion.


Localstack 一个功能齐全的本地AWS云堆栈

概述

LocalStack在本地计算机上启动以下核心云API, 离线开发和测试您的云和无服务器应用程序!

注:从版本开始0.11.0,所有API都通过单个边缘服务,可在以下位置访问http://localhost:4566默认情况下(可通过以下方式进行自定义EDGE_PORT,进一步见下文)

  • ACM
  • API网关
  • 云表单
  • CloudWatch
  • CloudWatch日志
  • DynamoDB
  • DynamoDB流
  • EC2
  • ElasticSearch服务
  • EventBridge(CloudWatch事件)
  • 消防水龙带
  • IAM
  • Kinesis
  • KMS
  • 兰姆达
  • 红移
  • 路由53
  • S3
  • 秘书经理
  • SES
  • SNS
  • SQS
  • SSM
  • 单步执行函数
  • STS

除上述外,Pro version of LocalStack支持其他API和高级功能,包括:

  • 放大
  • API网关V2(WebSockets支持)
  • 应用程序自动缩放
  • AppSync
  • 雅典娜
  • 备份
  • 批次
  • 云前端
  • 云迹(CloudTrail)
  • 科尼托
  • 成本资源管理器
  • ECS/ECR/EKS
  • ElastiCache
  • 弹性豆茎
  • ELB/ELBv2
  • 电子病历
  • 冰川/S3选择
  • IAM安全策略实施
  • 物联网
  • Kinesis数据分析
  • Lambda层和容器图像
  • 用于Kafka的托管流(MSK)
  • 媒体商店
  • 海王星图形DB
  • QLDB
  • RDS/Aurora无服务器
  • 时间流
  • 转接
  • X射线
  • 对大多数服务的高级持久性支持
  • 用于管理资源的交互式UI
  • 测试报告仪表板
  • 还有更多,更多的即将到来!(请查看我们的功能路线图这里:https://roadmap.localstack.cloud)

要求

  • python(最高支持Python 3.6至3.8)
  • pip(Python包管理器)
  • Docker
  • JDK(如果KINESIS_PROVIDERkinesis-mock并且该系统不是AMD64系统。支持8+个)

正在安装

安装LocalStack的最简单方法是通过pip

pip install localstack

注意事项如请务必照办。使用sudo或者rootUser-LocalStack应该完全在本地非root用户下安装和启动。如果您在MacOS X Sierra中的权限有问题,请使用安装pip install --user localstack

正在运行

默认情况下,LocalStack使用以下命令在Docker容器内启动:

localstack start

(请注意,在MacOS上,您可能需要运行TMPDIR=/private$TMPDIR localstack start --docker如果$TMPDIR包含Docker无法挂载的符号链接。)

注意事项:2020-07-11起,默认镜像localstack/localstackin Docker Hub指的是“轻量级版本”,它删除了一些大的依赖文件,比如Elasticsearch(如果需要,还可以懒惰地下载它们)。(请注意,localstack/localstack-light将来可能会删除图像别名)。如果您需要完整的依赖项集,localstack/localstack-full可以改为使用图像。请同时参阅USE_LIGHT_IMAGE下面的配置

注意事项:默认情况下,LocalStack使用标记的图像latest它缓存在您的计算机上,并且将自动从Docker Hub拉取最新镜像(即需要手动拉取镜像)

(注意事项:虽然强烈建议使用Docker,但也可以使用--host启动标志。请注意,这将需要additional dependencies,并且在某些操作系统(包括Windows)上不受支持。)

使用docker

您也可以直接使用docker,并使用以下命令开始使用localstack

docker run --rm -it -p 4566:4566 -p 4571:4571 localstack/localstack

若要在没有任何外部卷的情况下运行一次性容器,请执行以下操作。要启动服务子集,请使用-e "SERVICES=dynamodb,s3"

使用docker-compose

您也可以使用docker-compose.yml文件,然后使用此命令(当前需要docker-compose版本1.9.0+):

docker-compose up

(请注意,在MacOS上,您可能需要运行TMPDIR=/private$TMPDIR docker-compose up如果$TMPDIR包含Docker无法挂载的符号链接。)

为便于互操作性,配置变量可以作为前缀LOCALSTACK_在码头。例如,设置LOCALSTACK_SERVICES=s3相当于SERVICES=s3

使用头盔

您可以使用Helm通过运行以下命令在Kubernetes群集中安装LocalStack(Helm图表在中维护this repo):

helm repo add localstack-repo https://helm.localstack.cloud

helm upgrade --install localstack localstack-repo/localstack

配置

您可以将以下环境变量传递给LocalStack:

  • EDGE_PORT:边缘服务的端口号,所有API调用的主要入口点(默认值:4566)
  • SERVICES:要启动的服务名称(API)的逗号分隔列表。服务名称基本上对应于service names of the AWS CLI(kinesislambdasqs等),尽管LocalStack仅支持其中的一部分。示例值:kinesis,lambda,sqs启动Kinesis、Lambda和SQS。此外,可以指定以下速记值来运行预定义的服务集合:
    • serverless:运行通常用于无服务器应用程序的服务(iamlambdadynamodbapigateways3sns)
  • DEFAULT_REGION:与API通话时使用的AWS区域(默认值:us-east-1)
  • EDGE_BIND_HOST:边缘服务绑定到的地址。(默认值:127.0.0.1,在码头集装箱中0.0.0.0)
  • HOSTNAME:要在内部公开服务的主机的名称(默认值:localhost)。使用此选项来自定义框架内部通信,例如,如果使用docker-compose在不同容器中启动服务
  • HOSTNAME_EXTERNAL:要在外部公开服务的主机的名称(默认值:localhost)。例如,当将队列URL从SQS服务返回到客户端时,使用此主机
  • HOSTNAME_FROM_LAMBDA:端点主机,在该主机下可以从Lambda容器访问API(可选)。这在码头组成堆栈中使用本地容器主机名是有用的(例如,HOSTNAME_FROM_LAMBDA=localstack)如果主容器的IP地址和容器名称都不可用(例如,在CI中)。常与…连用LAMBDA_DOCKER_NETWORK
  • DEBUG:用于提高日志级别并打印更多详细日志的标志(用于故障排除)
  • <SERVICE>_PORT_EXTERNAL:向外部公开特定服务的端口号(默认为上面的服务端口)。SQS_PORT_EXTERNAL例如,将队列URL从SQS服务返回到客户端时使用
  • IMAGE_NAME:要使用的LocalStack Docker映像的特定名称和标签,例如,localstack/localstack:0.11.0(默认值:localstack/localstack)
  • USE_LIGHT_IMAGE:是否使用轻量级Docker镜像(默认为:1)。被覆盖IMAGE_NAME
  • KINESIS_PROVIDER:确定正在使用的模拟。有效值为kinesalitekinesis-mock(默认)
  • KINESIS_ERROR_PROBABILITY:0.0(默认值)和1.0之间的十进制值随机注入ProvisionedThroughputExceededExceptionKinesis API响应中的错误
  • KINESIS_SHARD_LIMIT:整数值(默认值:100)或Infinity(以禁用),导致Kinesis API开始引发异常以模仿default shard limit
  • KINESIS_LATENCY:毫秒整数值(默认值:500)或0(禁用),导致Kinesis API延迟返回响应,以模拟实时AWS调用的延迟。以下API调用受此影响:
    • CreateStream
    • 删除流
    • RegisterStreamConsumer
    • StartStreamEncryption
    • 停止流加密
    • DeregisterStreamConsumer
    • 合并碎片
    • 拆分碎片
    • 更新硬计数
  • KINESIS_INITIALIZE_STREAMS:以逗号分隔的流名称字符串及其对应的要在启动期间初始化的分片计数。例如:“my-first-stream:1,my-ther-stream:2,my-last-stream:1”。仅适用于kinesis-mockKinesis_Provider
  • DYNAMODB_ERROR_PROBABILITY:0.0(默认值)和1.0之间的十进制值随机注入ProvisionedThroughputExceededExceptionDynamoDB API响应中的错误
  • DYNAMODB_HEAP_SIZE:设置DynamoDB值的Java EE最大内存大小为(整数)m表示MB,(整数)G表示GB默认值(256M),全表扫描需要更多内存
  • STEPFUNCTIONS_LAMBDA_ENDPOINT:在STEP函数中用作Lambda服务端点的URL。默认情况下,这是LocalStack Lambda端点。使用default要选择原始AWS Lambda端点,请执行以下操作
  • LAMBDA_EXECUTOR:用于执行Lambda函数的方法。可能的值包括:
    • local:在本地计算机的临时目录中运行Lambda函数
    • docker:在单独的Docker容器中运行每个函数调用
    • docker-reuse:为每个函数创建一个Docker容器,并跨调用重用它

    dockerdocker-reuse,如果LocalStack本身在Docker内部启动,则docker命令需要在容器内可用(通常需要在特权模式下运行容器)。默认值为docker,回退到local如果Docker不可用

  • LAMBDA_REMOTE_DOCKER确定是否将Lambda代码复制或装载到容器中。可能的值包括:
    • true(默认):您的Lambda函数定义将通过复制zip文件传递到容器(可能较慢)。它允许远程执行,其中主机和客户端不在同一台计算机上
    • false:您的Lambda函数定义将通过挂载卷(可能更快)传递给容器。这需要将Docker客户端和Docker主机安装在同一台计算机上。另外,HOST_TMP_FOLDER必须正确设置,并且像这样的卷装载${HOST_TMP_FOLDER}:/tmp/localstack如果您使用的是docker-compose,则需要进行配置
  • BUCKET_MARKER_LOCAL:本地运行lambdas的可选存储桶名称
  • LAMBDA_DOCKER_NETWORK:可选Docker网络,用于运行lambda函数的容器
  • LAMBDA_DOCKER_DNS:运行lambda函数的容器的可选DNS服务器
  • LAMBDA_DOCKER_FLAGS:传递给Lambda Docker的其他标志run/create命令(例如,用于指定自定义卷装载)
  • LAMBDA_CONTAINER_REGISTRY使用备用docker注册表拉取lambda执行容器(默认:lambci/lambda)
  • LAMBDA_REMOVE_CONTAINERS:lambdas执行完毕后是否移除容器(默认:true)
  • TMPDIR:LocalStack容器内的临时文件夹(默认值:/tmp)
  • HOST_TMP_FOLDER:装载为的主机上的临时文件夹$TMPDIR/localstack放到LocalStack容器中。仅在使用时装载Lambda卷时需要LAMBDA_REMOTE_DOCKER=false
  • DATA_DIR:保存持久数据的本地目录(目前仅支持以下服务:Kinesis、DynamoDB、Elasticsearch、S3、Secretsmanager、SSM、SQS、SNS)。将其设置为/tmp/localstack/data要启用持久性(/tmp/localstack挂载到Docker容器中),则保留为空以禁用持久化(默认)
  • PERSISTENCE_SINGLE_FILE:指定是否应合并持久性文件。(默认值:true)
  • PORT_WEB_UI:Web用户界面/仪表板的端口(默认:8080)。请注意,Web UI现在已弃用(需要使用激活START_WEB=1),并要求使用localstack/localstack-fullDocker镜像
  • <SERVICE>_BACKEND:用于特定服务的自定义端点URL,其中<SERVICE>是大写的服务名称(当前适用于:APIGATEWAYCLOUDFORMATIONDYNAMODBELASTICSEARCHKINESISS3SNSSQS)。这样就可以轻松地将第三方服务集成到LocalStack中。您可以查看一个elasticsearch example here
  • FORCE_NONINTERACTIVE:使用Docker运行时,禁用--interactive--tty旗帜。在无头运行时很有用
  • DOCKER_FLAGS:允许在Docker中运行LocalStack时将自定义标志(例如,卷装载)传递给“docker run”
  • DOCKER_CMD:用于运行Docker容器的shell命令,例如,设置为"sudo docker"以sudo身份运行(默认值:docker)
  • SKIP_INFRA_DOWNLOADS:是否跳过下载其他基础架构组件(例如,特定的Elasticsearch版本)
  • START_WEB:用于控制是否应在Docker中启动Web UI的标志(默认值:false;已弃用)
  • LAMBDA_FALLBACK_URL:调用不存在的Lambda时使用的回退URL。记录DynamoDB(值)中的调用dynamodb://<table_name>)或将调用作为POST请求(值http(s)://...)
  • LAMBDA_FORWARD_URL:用于转发所有lambda调用的URL(用于通过外部服务运行lambdas)
  • DISABLE_CORS_CHECKS:是否禁用所有CSRF缓解(默认值:0)
  • DISABLE_CUSTOM_CORS_S3:是否通过S3禁用CORS覆盖(默认值:0)
  • DISABLE_CUSTOM_CORS_APIGATEWAY:禁用由apigateway覆盖CORS的内容(默认值:0)
  • EXTRA_CORS_ALLOWED_ORIGINS:允许与本地堆栈通信的来源的逗号分隔列表
  • EXTRA_CORS_ALLOWED_HEADERS:要添加到的以逗号分隔的标头名称列表Access-Control-Allow-HeadersCORS标头
  • EXTRA_CORS_EXPOSE_HEADERS:要添加到的以逗号分隔的标头名称列表Access-Control-Expose-HeadersCORS标头
  • LAMBDA_JAVA_OPTS:允许传递自定义JVM选项(例如,-Xmx512M)到在Docker中执行的Java lambdas。使用_debug_port_用于配置调试端口的占位符(例如,-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=_debug_port_)
  • MAIN_CONTAINER_NAME:指定主坞容器名称(默认值:localstack_main)
  • INIT_SCRIPTS_PATH:指定扩展名为.sh的初始化文件的路径,这些文件默认位于/docker-entrypoint-initaws.d
  • LS_LOG:指定日志级别(‘trace’、‘debug’、‘info’、‘warn’、‘error’、‘warning’)当前重写DEBUG配置。启用LS_LOG=trace打印详细的请求/响应消息

以下环境配置可用于调试:

  • DEVELOP:在启动本地堆栈服务之前启动调试服务器
  • DEVELOP_PORT:调试服务器的端口号
  • WAIT_FOR_DEBUGGER:强制LocalStack等待调试器启动服务

以下环境配置包括已弃用

  • USE_SSL:是否使用https://...使用SSL加密的URL(默认值:false)。从版本0.11.3起不建议使用-每个服务端点现在都支持在同一端口上多路传输HTTP/HTTPS流量

此外,还包括以下内容只读环境变量可用:

  • LOCALSTACK_HOSTNAME:LocalStack服务可用的主机的名称。使用该主机名作为端点(例如,http://${LOCALSTACK_HOSTNAME}:4566)以便从Lambda函数中访问服务(例如,将项从Lambda存储到DynamoDB或S3)

将上述环境变量传递给LocalStack以启动Kinesis、Lambda、DynamoDB和SQS的示例:

SERVICES=kinesis,lambda,sqs,dynamodb localstack start

使用命令行验证坞站合成配置

您可以使用localstack config validate用于检查常见配置错误的命令

默认情况下,它会验证docker-compose.yml,则可以使用--file参数,例如:

localstack config validate --file=localstack-docker-compose.yml

在运行时动态更新配置

列出的每个服务APIabove在PATH下定义后门API/?_config_中定义的配置变量,它允许动态更新config.py

您需要通过设置来启用此终结点ENABLE_CONFIG_UPDATES=1

例如,要动态设置KINESIS_ERROR_PROBABILITY=1在运行时,使用以下命令:

curl -v -d '{"variable":"KINESIS_ERROR_PROBABILITY","value":1}' 'http://localhost:4566/?_config_'

服务运行状况检查

这项服务/health检查边缘端口上的端点(http://localhost:4566/health默认情况下)提供关于每个服务的状态的基本信息(例如,{"s3":"running","es":"starting"})。默认情况下,端点返回在启动期间确定的缓存值-状态值可以通过添加reload查询参数:http://localhost:4566/health?reload

初始化新实例

首次启动容器时,它将执行扩展名为.sh的文件,这些文件位于/docker-entrypoint-initaws.d或中定义的备用路径INIT_SCRIPTS_PATH文件将按字母顺序执行。您可以使用以下命令在本地堆栈上轻松创建AWS资源awslocal(或aws)初始化脚本中的CLI工具

使用自定义SSL证书

要使用您自己的SSL证书而不是随机生成的证书,您可以放置一个文件server.test.pem放入LocalStack临时目录($TMPDIR/localstack,或/tmp/localstack默认情况下)。该文件server.test.pem必须包含密钥文件以及证书文件内容:

-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

将自定义SSL证书与docker-compose配合使用

通常,使用docker-compose可以将此卷添加到docker-compose.yml到LocalStack服务中:

  volumes:
    - "${PWD}/ls_tmp:/tmp/localstack"
    - "/var/run/docker.sock:/var/run/docker.sock"

本地目录/ls_tmp必须包含三个文件(server.test.pem、server.test.pem.crt、server.test.pem.key)

通过CLI或代码访问基础架构

你可以把你的aws使用本地基础架构的CLI,例如:

aws --endpoint-url=http://localhost:4566 kinesis list-streams
{
    "StreamNames": []
}

使用以下命令安装aws CLI,如果尚未安装

pip install awscli

设置本地区域和凭据以运行LocalStack

AWS需要设置区域和凭证才能运行AWS命令。创建默认配置&凭据。以下密钥将要求提供访问密钥ID、秘密访问密钥、区域和输出格式

aws configure --profile default

# Config & credential file will be created under ~/.aws folder

注意事项:请使用test作为访问密钥ID和秘密访问密钥,以使S3预签名URL工作。我们增加了前缀url签名验证算法来验证前缀url及其有效期。您可以使用将凭据配置到系统环境中export命令在Linux/Mac系统中运行。您还可以在中添加凭据~/.aws/credentials直接归档

export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test

新的:退房awslocal,一个直接针对LocalStack运行命令的精简CLI包装器(无需指定--endpoint-url再也没有了)。通过以下方式安装pip install awscli-local,然后按如下方式使用:

awslocal kinesis list-streams
{
    "StreamNames": []
}

更新:使用环境变量$LOCALSTACK_HOSTNAME来确定lambda函数中的目标主机。看见Configurations部分了解更多详细信息。

将官方AWS CLI版本2 Docker映像与Localstack Docker容器配合使用

默认情况下,运行的容器amazon/aws-cli0.0.0.0:4566在主机上,这意味着aws-cli无法通过您的shell访问本地堆栈

要确保两个坞站容器可以通信,请在坞站引擎上创建网络:

$ ▶ docker network create localstack
0c9cb3d37b0ea1bfeb6b77ade0ce5525e33c7929d69f49c3e5ed0af457bdf123

然后修改docker-compose.yml指定要使用的网络:

networks:
  default:
    external:
      name: "localstack"

使用此网络运行AWS Cli v2坞站容器(示例):

$ ▶ docker run --network localstack --rm -it amazon/aws-cli --endpoint-url=http://localstack:4566 lambda list-functions
{
    "Functions": []
}

如果您经常从坞站容器使用AWS CLI v2,请创建别名:

$ ▶ alias laws='docker run --network localstack --rm -it amazon/aws-cli --endpoint-url=http://localstack:4566'

因此,您可以键入:

$ ▶ laws lambda list-functions
{
    "Functions": []
}

客户端库

正在调用API网关

而AWS上的API网关端点使用自定义DNS名称来标识API ID(例如,https://nmafetnwf6.execute-api.us-east-1.amazonaws.com/prod/my/path),LocalStack使用特殊的URL路径指示符.../_user_request_/...指示睡觉API方法的执行

API网关执行的URL模式为http://localhost:4566/restapis/<apiId>/<stage>/_user_request_/<methodPath>上面的示例URL将映射到以下内容localhostURL:

$ curl http://localhost:4566/restapis/nmafetnwf6/prod/_user_request_/my/path

与pytest集成

如果您想在集成测试中使用LocalStack(例如pytest),只需启动测试设置方法中的基础设施,然后清除tearDown方法中的所有内容:

from localstack.services import infra

def setup():
    infra.start_infra(asynchronous=True)

def teardown():
    infra.stop_infra()

def my_app_test():
    # here goes your test logic

请参阅示例测试文件tests/integration/test_integration.py有关更多详细信息,请参阅

与无服务器集成

您可以使用serverless-localstack易于运行的插件ServerlessLocalStack上的应用程序。有关更多信息,请查看此处的插件存储库:https://github.com/localstack/serverless-localstack

与Terraform集成

您可以使用Terraform在本地配置您的资源。请参阅Terraform AWS提供商文档here有关如何在上配置API端点的信息localhost

将本地代码与Lambda一起使用

要挂载本地文件夹,请确保LAMBDA_REMOTE_DOCKER设置为false然后将S3存储桶名称设置为__local__BUCKET_MARKER_LOCAL如果已设置,并且S3键指向您的本地路径:

awslocal lambda create-function --function-name myLambda \
    --code S3Bucket="__local__",S3Key="/my/local/lambda/folder" \
    --handler index.myHandler \
    --runtime nodejs8.10 \
    --role whatever

注:在使用时LAMBDA_REMOTE_DOCKER=false,请确保正确设置HOST_TMP_FOLDERLocalStack容器的环境变量(请参见上面的配置部分)

与Java/JUnit集成

为了在Java中使用LocalStack,该项目附带了一个简单的JUnit运行器,请参见下面的示例

...
import cloud.localstack.LocalstackTestRunner;
import cloud.localstack.TestUtils;
import cloud.localstack.docker.annotation.LocalstackDockerProperties;

@RunWith(LocalstackTestRunner.class)
@LocalstackDockerProperties(services = { "s3", "sqs", "kinesis:77077" })
public class MyCloudAppTest {

  @Test
  public void testLocalS3API() {
    AmazonS3 s3 = TestUtils.getClientS3()
    List<Bucket> buckets = s3.listBuckets();
    ...
  }
}

有关更多详细信息和配置参数的完整列表,请参阅LocalStack Java Utils存储库

故障排除

  • 如果您将AWS Java库与Kinesis配合使用,请参阅CBOR protocol issues with the Java SDK guide如何禁用kinesalite不支持的CBOR协议
  • 访问本地S3:为避免域名解析问题,需要开启路径样式访问在您的S3SDK客户端上。大多数AWS SDK都提供配置来实现这一点,例如,对于Java:
s3.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).build());
// There is also an option to do this if you're using any of the client builder classes:
AmazonS3ClientBuilder builder = AmazonS3ClientBuilder.standard();
builder.withPathStyleAccessEnabled(true);
...
  • 正在挂载临时工。目录:请注意,在MacOS上,您可能必须运行TMPDIR=/private$TMPDIR docker-compose up如果$TMPDIR包含Docker无法挂载的符号链接。(请在此处查看详细信息:https://bitbucket.org/atlassian/localstack/issues/40/getting-mounts-failed-on-docker-compose-up)
  • 如果您看到像这样的Lambda错误Cannot find module ...在使用时LAMBDA_REMOTE_DOCKER=false,请确保正确设置HOST_TMP_FOLDER环境变量,并将临时文件夹从主机挂载到LocalStack容器
  • 如果您在以下位置遇到文件权限问题pip install在MacOS下(例如,Permission denied: '/Library/Python/2.7/site-packages/six.py'),则您可能需要重新安装pipVia Homebrew(请参见this discussion thread)。或者,尝试使用--user标志:pip install --user localstack
  • 如果您在OpenShift内部署,请注意:Pod必须以root,并且用户必须将权能添加到正在运行的Pod中,才能允许Elasticsearch作为非根用户运行localstack用户
  • 如果您在Mac OS中遇到lambdas性能较慢的问题,您可以(1)尝试mounting local code directly into the Lambda container,或(2)禁止在docker-compose中将临时目录挂载到LocalStack容器中。(另见https://github.com/localstack/localstack/issues/2515)
  • 环境变量no_proxy由LocalStack重写。(内部请求将直接通过localhost,绕过任何代理配置)
  • 要对LocalStack启动问题进行故障排除,可以通过运行以下命令检查调试日志DEBUG=1 localstack start
  • 如果您遇到与Node/NodeJS相关的错误,您可以找到(此问题备注:https://github.com/localstack/localstack/issues/227#issuecomment-319938530)很有帮助
  • 如果您正在使用AWS Java库并需要禁用SSL证书检查,请添加-Dcom.amazonaws.sdk.disableCertChecking添加到java调用

发展中的

在本地开发或启动的要求

要开发新功能,或在本地启动堆栈(在Docker之外),需要以下附加工具:

  • make
  • npm(Node.js包管理器)
  • java/javac(Java 8运行时环境和编译器)
  • mvn(Maven,Java的构建系统)
  • moto(用于测试)
  • docker-compose(用于使用docker-compose运行本地堆栈)
  • mock(用于单元测试)
  • pytest(用于单元测试)
  • pytest-cov(检查单元测试覆盖率)

开发环境

如果为了扩展/修改LocalStack而拉回回购,请运行以下命令以安装所有依赖项:

make install

这将在本地Python viralenv目录中安装所需的pip依赖项.venv(您的全局python包将保持不变),以及中的一些节点模块。./localstack/node_modules/根据您的系统,某些pip/npm模块可能需要安装其他本地库。

Makefile包含一个目标,用于方便地运行用于开发的本地基础设施:

make infra

使用Vagant启动LocalStack(CentOS 8)

这类似于make docker-mount-run,但不是启动docker centos虚拟机,而是将源代码挂载到其中

前提条件
  • 流浪汉
  • vagrant plugin install vagrant-vbguest
启动流浪汉
  • make vagrant-start(准备好提供系统密码)
使用流浪汉
  • vagrant ssh
  • sudo -s
  • cd /localstack
  • SERVICES=dynamodb DEBUG=1 make docker-mount-run
停止流浪汉
  • make vagrant-stopvagrant halt
删除流浪VM
  • vagrant destroy

请查看developer guide其中包含一些关于如何开始开发(和调试)LocalStack功能的说明

测试

该项目包含一组可以通过make目标启动的单元和集成测试:

make test

要检查代码覆盖率,请执行以下操作

完成新功能/错误修复后,运行单元测试并检查覆盖范围

# To run the particular test file (sample)
pytest --cov=localstack tests/unit/test_common.py

# To check the coverage in the console
coverage report

# To check the coverage as html (output will be redirected to the html folder)
coverage html

Web仪表板(已弃用)

这些项目还附带一个简单的Web仪表板,可用于查看已部署的AWS组件以及它们之间的关系

localstack web

请注意,Web UI需要使用Docker映像的扩展版本(localstack/localstack-full)

注:Web仪表板不再进行主动维护,可能会在即将发布的版本中删除

其他UI客户端

更改日志

请参阅CHANGELOG.md要查看每个版本的完整更改列表,请执行以下操作

贡献

我们欢迎反馈、错误报告和拉请求!

对于拉取请求,请遵循以下指导原则:

  • 添加对任何新功能和错误修复的测试。理想情况下,每个PR都应该增加测试覆盖率
  • 遵循现有代码样式(例如,缩进)。Makefile中包含PEP8代码链接目标
  • 在代码中添加合理数量的注释
  • 在您的GitHub用户帐户上派生本地堆栈,在那里进行更改,然后根据主本地堆栈存储库创建PR
  • 将不相关的更改分离到多个拉取请求中
  • 每个PR 1个提交:请将多个提交压缩/重新设置为单个提交的基础(以保持历史记录的干净)

请注意,通过向此存储库贡献任何代码或文档(通过提出拉请求或其他方式),您明确同意Contributor License Agreement

贡献者

这个项目的存在要归功于所有做出贡献的人。

支持者

感谢我们所有的支持者!🙏[Become a backer]

赞助商

通过成为赞助商来支持这个项目。您的徽标将在此处显示,并带有指向您的网站的链接。[Become a sponsor]










随时间流逝的观星者

许可证

版权所有(C)2017-2020 LocalStack维护者和贡献者

版权所有(C)2016 Atlassian和其他

此版本的LocalStack是在Apache许可证2.0版(请参阅LICENSE.txt)下发布的。下载并使用本软件,即表示您同意End-User License Agreement (EULA)

我们基于多个第三方软件工具构建,包括:

第三方软件 许可证
Python/pip模块:
空速 BSD许可证
Amazon_kclpy 亚马逊软件许可证
Boto3 Apache License 2.0
覆盖范围 Apache License 2.0
文档选项 麻省理工学院许可证
弹性搜索 Apache License 2.0
烧瓶 BSD许可证
烧瓶招摇过市 麻省理工学院许可证
jsonpath-RW Apache License 2.0
摩托 Apache License 2.0
请求 Apache License 2.0
子进程32 PSF许可证
Node.js/npm模块:
活塞利特(Kinesalite) 麻省理工学院许可证
其他工具:
弹性搜索 Apache License 2.0
本地-KMS 麻省理工学院许可证
Kinesis-模拟 麻省理工学院许可证

公告

  • 2021-04-24我们要招人了!-如果您喜欢我们在LocalStack所做的工作,请查看我们的jobs board然后给我们发一封电子邮件,告诉我们你的简历/背景/投资组合。我们期待着您的回音!
  • 2020/12/28:查看LocalStack Pro功能路线图这里:https://roadmap.localstack.cloud-请通过创建和提升功能请求来帮助我们确定积压工作的优先顺序。期待您的反馈!
  • 2020-09-15:PR#2905中合并了一个重大(突破性)更改-从以下版本开始v0.11.5,所有服务现在仅通过边缘服务(端口4566)公开!请更新您的客户端配置以使用此新端点
  • 2019-10-09LocalStack Pro已推出!我们非常兴奋地宣布推出LocalStack Pro-具有附加API和高级功能的LocalStack企业版。请访问以下地址查看免费试用https://localstack.cloud
  • 2018-01-10需要帮助!fill out this survey支持查尔默斯理工大学进行的一项关于无服务器和功能即服务(FAAS)服务使用情况的研究。调查只需要你5-10分钟的时间。非常感谢您的参与!!
    • 这项研究的结果是可以找到的here
  • 2017-08-27我们需要你的支持!LocalStack正在快速发展,我们现在有数千名开发人员定期使用该平台。上个月,我们记录了惊人的100k测试运行,25k+DynamoDB表、20k+SQS队列、15k+Kinesis Streams、13k+S3存储桶和10k+Lambda函数在本地创建-成本为0美元(更多详细信息将很快公布)。bug和功能请求如潮水般涌入,我们现在需要来自保持开放源码版本的积极维护。请给我退房Open Collective并成为一名backersupporter今天是项目的第一天!谢谢大家的贡献。♥
  • 2017/07/20:请注意:从版本开始0.7.0,将推送Docker映像并使其处于最新状态新名称localstack/localstack(这意味着您可能需要更新您的配置项配置。)请参阅更新后的End-User License Agreement (EULA)用于新版本。旧的Docker映像(atlassianlabs/localstack)仍然可用,但不会再维护