Packaging, Distribution and Deployment

52.1 A CPAN-Style Distribution

Authoring tools: Dist::Zilla (dzil build/test/release), Minilla (minil), Module::Starter (scaffolding), App::ModuleBuildTiny. Release to CPAN through PAUSE (the Perl Authors Upload Server).

My-Tool/
├── lib/My/Tool.pm
├── bin/mytool
├── t/00-load.t
├── xt/author/critic.t      # author-only tests
├── Makefile.PL             # or Build.PL / dist.ini / minil.toml
├── cpanfile
├── Changes
├── README.md
├── LICENSE
└── MANIFEST
# Makefile.PL (ExtUtils::MakeMaker, core)
use ExtUtils::MakeMaker;
WriteMakefile(
    NAME         => 'My::Tool',
    VERSION_FROM => 'lib/My/Tool.pm',
    EXE_FILES    => ['bin/mytool'],
    PREREQ_PM    => { 'Moo' => 2, 'JSON::MaybeXS' => 0 },
    TEST_REQUIRES => { 'Test2::V0' => 0 },
    MIN_PERL_VERSION => '5.036',
    LICENSE      => 'perl_5',
);
perl Makefile.PL && make && make test && make install
make dist                      # creates My-Tool-1.00.tar.gz

52.2 Deployment Options

Carton + cpanfile.snapshot Reproducible dependencies (like a lockfile)

FROM perl:5.40-slim, cpanm --installdeps ., multi-stage builds

Pack pure-Perl dependencies into a single script PAR::Packer (pp)

Build standalone executables (bundles perl + modules) dh-make-perl (Debian), cpanspec (RPM)

Isolate the application's Perl from the system Perl systemd / supervisord

Run web apps and daemons (Hypnotoad, Starman)

FROM perl:5.40-slim
WORKDIR /app
RUN cpanm -n Carton
COPY cpanfile cpanfile.snapshot ./
RUN carton install --deployment
COPY . .
EXPOSE 8080
CMD ["carton", "exec", "hypnotoad", "-f", "script/myapp"]

52.3 CI

# .github/workflows/test.yml
name: test
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        perl: ['5.36', '5.38', '5.40']
    container: perl:${{ matrix.perl }}
    steps:
      - uses: actions/checkout@v4
      - run: cpanm -n --installdeps --with-develop .
      - run: prove -lr -j4 t/
      - run: perlcritic --severity 3 lib/