In lack of any support, I have simply used machine: true
to run my jobs on VMs and then simply run the same Docker image via my Makefile.
In order for file permissions to work properly, I had to write a script that runs in the container on init which moves UIDs and GIDs for the circleci
user in the container to match the host: https://github.com/naftulikay/docker-circleci-lambda-rust/blob/master/bin/id-remap
In some strange twist of fate, usermod
and groupmod
together take a whopping 30 seconds in the container while find $HOME -exec chown -R $USER:$USER {} \;
takes only a few seconds.
My effective CircleCI 2 configuration:
---
version: 2
jobs:
build:
machine: true
steps:
- checkout
- restore_cache:
keys:
- v1-project-cache-{{ .Branch }}-{{ .Revision }}
- v1-project-cache-{{ .Branch }}
- run:
name: PULL!
command: make pull
- run:
name: Test
command: make test
- run:
name: Build
command: make build
- save_cache:
key: v1-project-cache-{{ .Branch }}-{{ .Revision }}
paths:
- "~/.cargo"
- "~/.cache/cargo"
- "./target"
- save_cache:
key: v1-project-cache-{{ .Branch }}
paths:
- "~/.cargo"
- "~/.cache/cargo"
- "./target"
deploy:
machine: true
steps:
- restore_cache:
keys:
- v1-project-cache-{{ .Branch }}-{{ .Revision }}
- v1-project-cache-{{ .Branch }}
- run:
name: Deploy
command: make deploy
workflows:
version: 2
release:
jobs:
- build
- deploy:
requires: [build]
filters:
branches:
only: master
And my Makefile
:
#!/usr/bin/make -f
LAMBDA_FUNCTION_NAME:=api-naftuli-wtf
REST_API_ID:=smddwihyy9
STAGE:=production
CACHE_DIR:=$(HOME)/.cache/cargo
ZIP_FILE:=$(CACHE_DIR)/target/deploy/lambda.zip
DOCKER_IMAGE:=naftulikay/circleci-lambda-rust:latest
WORKDIR:=$(shell pwd)
USER_UID:=$(shell id -u)
USER_GID:=$(shell id -g)
IS_TTY:=$(shell test -t && echo '-t')
DOCKER_INVOKE:=docker run -i $(IS_TTY) --rm \
-e USER_UID=$(USER_UID) \
-e USER_GID=$(USER_GID) \
-v $(WORKDIR):/home/circleci/project \
-v $(CACHE_DIR)/cargo/registry:/home/circleci/.cargo/registry \
-v $(CACHE_DIR)/target:/home/circleci/project/target \
-v $(WORKDIR)/bin:/home/circleci/.local/bin \
$(DOCKER_IMAGE)
init:
@mkdir -p target/deploy
pull:
@docker pull $(DOCKER_IMAGE)
build: init
@$(DOCKER_INVOKE) .local/bin/build
@cp $(ZIP_FILE) target/deploy
test: init
@$(DOCKER_INVOKE) .local/bin/test
clean: init
@$(DOCKER_INVOKE).local/bin/clean
shell: init
@$(DOCKER_INVOKE)
deploy: build
@# update the function
aws --region us-east-1 lambda update-function-code --function-name $(LAMBDA_FUNCTION_NAME) \
--zip-file fileb://$(ZIP_FILE)
@# deploy the api
aws --region us-east-1 apigateway create-deployment --rest-api-id $(REST_API_ID) --stage-name $(STAGE)
This allows me to effectively build my artifacts both from Vagrant and CircleCI.
It’s clearly an abuse of the system, but it works.