--- description: Set up GitHub Actions CI/CD pipeline for Rust Lambda deployment --- You are helping the user set up a GitHub Actions workflow for automated Lambda deployment. ## Your Task Create a complete GitHub Actions workflow for building, testing, and deploying Rust Lambda functions. 1. **Ask about deployment preferences**: - Which AWS region(s)? - Which architecture (x86_64, arm64, or both)? - Deploy on every push to main, or only on tags/releases? - AWS authentication method (OIDC or access keys)? - Single function or multiple functions? 2. **Create workflow file**: Create `.github/workflows/deploy-lambda.yml` with appropriate configuration 3. **Set up AWS authentication**: - OIDC (recommended, more secure) - Access keys (simpler setup) 4. **Configure required secrets** in GitHub repo settings ## Complete Workflow Examples ### Option 1: OIDC Authentication (Recommended) ```yaml name: Deploy Lambda on: push: branches: [ main ] pull_request: branches: [ main ] env: CARGO_TERM_COLOR: always AWS_REGION: us-east-1 jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Cache cargo dependencies uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Run tests run: cargo test --verbose - name: Run clippy run: cargo clippy -- -D warnings - name: Check formatting run: cargo fmt -- --check build-and-deploy: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' permissions: id-token: write # Required for OIDC contents: read steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Cache cargo dependencies uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Install Zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.11.0 - name: Install cargo-lambda run: pip install cargo-lambda - name: Build Lambda (ARM64) run: cargo lambda build --release --arm64 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ${{ env.AWS_REGION }} - name: Deploy to AWS Lambda run: | cargo lambda deploy \ --iam-role ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} \ --region ${{ env.AWS_REGION }} \ --arch arm64 - name: Test deployed function run: | aws lambda invoke \ --function-name ${{ secrets.LAMBDA_FUNCTION_NAME }} \ --payload '{"test": true}' \ response.json cat response.json ``` ### Option 2: Access Keys Authentication ```yaml name: Deploy Lambda on: push: branches: [ main ] pull_request: branches: [ main ] env: CARGO_TERM_COLOR: always AWS_REGION: us-east-1 jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Cache cargo dependencies uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Run tests run: cargo test --verbose build-and-deploy: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Cache cargo dependencies uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Install Zig uses: goto-bus-stop/setup-zig@v2 with: version: 0.11.0 - name: Install cargo-lambda run: pip install cargo-lambda - name: Build Lambda (ARM64) run: cargo lambda build --release --arm64 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ env.AWS_REGION }} - name: Deploy to AWS Lambda run: | cargo lambda deploy \ --iam-role ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} \ --region ${{ env.AWS_REGION }} \ --arch arm64 ``` ### Option 3: Multi-Architecture Build ```yaml name: Deploy Lambda on: push: branches: [ main ] release: types: [ published ] env: CARGO_TERM_COLOR: always jobs: build-matrix: strategy: matrix: include: - arch: x86_64 aws_arch: x86_64 build_flags: "" - arch: arm64 aws_arch: arm64 build_flags: "--arm64" runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Install Zig uses: goto-bus-stop/setup-zig@v2 - name: Install cargo-lambda run: pip install cargo-lambda - name: Build for ${{ matrix.arch }} run: cargo lambda build --release ${{ matrix.build_flags }} --output-format zip - name: Upload artifact uses: actions/upload-artifact@v4 with: name: lambda-${{ matrix.arch }} path: target/lambda/**/*.zip deploy: needs: build-matrix runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' permissions: id-token: write contents: read strategy: matrix: arch: [arm64, x86_64] steps: - uses: actions/checkout@v4 - name: Download artifact uses: actions/download-artifact@v4 with: name: lambda-${{ matrix.arch }} path: target/lambda - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: us-east-1 - name: Install cargo-lambda run: pip install cargo-lambda - name: Deploy ${{ matrix.arch }} run: | cargo lambda deploy my-function-${{ matrix.arch }} \ --iam-role ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} \ --arch ${{ matrix.arch }} ``` ### Option 4: Multiple Functions ```yaml name: Deploy Lambda Functions on: push: branches: [ main ] env: CARGO_TERM_COLOR: always AWS_REGION: us-east-1 jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - run: cargo test --all deploy: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' permissions: id-token: write contents: read strategy: matrix: function: - name: api-handler memory: 512 timeout: 30 - name: data-processor memory: 2048 timeout: 300 - name: event-consumer memory: 1024 timeout: 60 steps: - uses: actions/checkout@v4 - name: Install Rust uses: dtolnay/rust-toolchain@stable - name: Install Zig uses: goto-bus-stop/setup-zig@v2 - name: Install cargo-lambda run: pip install cargo-lambda - name: Build ${{ matrix.function.name }} run: cargo lambda build --release --arm64 --bin ${{ matrix.function.name }} - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ${{ env.AWS_REGION }} - name: Deploy ${{ matrix.function.name }} run: | cargo lambda deploy ${{ matrix.function.name }} \ --iam-role ${{ secrets.LAMBDA_EXECUTION_ROLE_ARN }} \ --region ${{ env.AWS_REGION }} \ --memory ${{ matrix.function.memory }} \ --timeout ${{ matrix.function.timeout }} \ --arch arm64 \ --env-var RUST_LOG=info ``` ## AWS OIDC Setup For OIDC authentication (recommended), set up in AWS: ### 1. Create OIDC Provider in AWS IAM ```bash aws iam create-open-id-connect-provider \ --url https://token.actions.githubusercontent.com \ --client-id-list sts.amazonaws.com \ --thumbprint-list 6938fd4d98bab03faadb97b34396831e3780aea1 ``` ### 2. Create IAM Role for GitHub Actions ```bash # Create trust policy cat > github-actions-trust-policy.json <> $GITHUB_OUTPUT - name: Deploy with version tag run: | cargo lambda deploy \ --tags Version=${{ steps.tag.outputs.version }} ``` ### Environment-Specific Deployment ```yaml on: push: branches: - main - develop jobs: deploy: runs-on: ubuntu-latest steps: - name: Set environment id: env run: | if [ "${{ github.ref }}" = "refs/heads/main" ]; then echo "name=production" >> $GITHUB_OUTPUT echo "suffix=" >> $GITHUB_OUTPUT else echo "name=development" >> $GITHUB_OUTPUT echo "suffix=-dev" >> $GITHUB_OUTPUT fi - name: Deploy run: | cargo lambda deploy my-function${{ steps.env.outputs.suffix }} \ --env-var ENVIRONMENT=${{ steps.env.outputs.name }} ``` ### Conditional Deployment ```yaml - name: Check if Lambda code changed id: lambda-changed uses: dorny/paths-filter@v2 with: filters: | lambda: - 'src/**' - 'Cargo.toml' - 'Cargo.lock' - name: Deploy Lambda if: steps.lambda-changed.outputs.lambda == 'true' run: cargo lambda deploy ``` ### Slack Notifications ```yaml - name: Notify Slack on success if: success() uses: slackapi/slack-github-action@v1 with: payload: | { "text": "Lambda deployed successfully: ${{ github.repository }}" } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} ``` ## Performance Optimizations ### Faster Builds with Caching ```yaml - name: Cache Rust uses: Swatinem/rust-cache@v2 with: cache-on-failure: true ``` ### Parallel Jobs ```yaml jobs: test: # Testing job build: # Build job (independent of test for speed) deploy: needs: [test, build] # Only deploy if both succeed ``` ## Troubleshooting CI/CD ### Issue: "cargo-lambda: command not found" **Solution**: Ensure `pip install cargo-lambda` runs before use ### Issue: "Zig not found" **Solution**: Add `goto-bus-stop/setup-zig@v2` step ### Issue: "AWS credentials not configured" **Solution**: Verify secrets are set and aws-actions step is included ### Issue: Build caching not working **Solution**: Use `Swatinem/rust-cache@v2` for better Rust caching ### Issue: Deployment fails intermittently **Solution**: Add retry logic or use `aws lambda wait function-updated` ## Testing the Workflow 1. **Create workflow file** in `.github/workflows/deploy-lambda.yml` 2. **Configure secrets** in GitHub settings 3. **Push to trigger**: ```bash git add .github/workflows/deploy-lambda.yml git commit -m "Add Lambda deployment workflow" git push ``` 4. **Monitor** in GitHub Actions tab 5. **Check logs** for any issues ## Best Practices 1. **Always run tests** before deployment 2. **Use OIDC** instead of long-lived credentials 3. **Cache dependencies** for faster builds 4. **Deploy on main branch** only, test on PRs 5. **Use matrix builds** for multiple architectures 6. **Tag deployments** with version info 7. **Add notifications** for deployment status 8. **Set up monitoring** and alerts in AWS 9. **Use environments** for production deployments 10. **Document secrets** needed in README After creating the workflow, guide the user through: 1. Setting up required secrets 2. Testing the workflow 3. Monitoring deployments 4. Handling failures