Skip to content

Commit bf14882

Browse files
committed
Prepare DevoxxFR
Signed-off-by: Jean-Christophe Sirot <jcsirot@gmail.com>
1 parent abde035 commit bf14882

File tree

5 files changed

+117
-121
lines changed

5 files changed

+117
-121
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Build and Test with Dagger
2+
on:
3+
pull_request:
4+
types: [opened, synchronize]
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
build:
11+
name: build
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Build and test
18+
id: build-and-test
19+
uses: dagger/dagger-for-github@8.0.0
20+
with:
21+
version: "0.16.3"
22+
verb: call
23+
args: build-and-test
24+
cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }}

.github/workflows/deploy-with-dagger.yaml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@ jobs:
1010
build:
1111
name: build, publish
1212
runs-on: ubuntu-latest
13+
outputs:
14+
image: ${{ steps.publish.outputs.output }}
1315
steps:
1416
- name: Checkout
1517
uses: actions/checkout@v4
1618

1719
- name: Build and publish image
1820
id: publish
19-
uses: dagger/dagger-for-github@v7
21+
uses: dagger/dagger-for-github@8.0.0
2022
with:
21-
version: "latest"
23+
version: "0.16.3"
2224
verb: call
23-
args: publish --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY
25+
args: build-and-push-image --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY --repo-name=${{ vars.REPO_NAME }} --account-id=${{ vars.ACCOUNT_ID }} --region=${{ vars.AWS_REGION }}
2426
cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }}
2527

2628
deploy:
@@ -29,17 +31,17 @@ jobs:
2931
needs: build
3032
steps:
3133
- name: Deploy to K8S
32-
uses: dagger/dagger-for-github@v7
34+
uses: dagger/dagger-for-github@8.0.0
3335
with:
34-
version: "latest"
36+
version: "0.16.3"
3537
verb: call
36-
args: deploy --image=${{ steps.publish.outputs.output }} --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY --cluster-name ${{ vars.CLUSTER_NAME }}
38+
args: deploy --image=${{ needs.build.outputs.image }} --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY --cluster-name ${{ vars.CLUSTER_NAME }}
3739
cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }}
3840

3941
- name: Get Public URL
40-
uses: dagger/dagger-for-github@v7
42+
uses: dagger/dagger-for-github@8.0.0
4143
with:
42-
version: "latest"
44+
version: "0.16.3"
4345
verb: call
4446
args: get-ingress --aws-access-key-id=env://AWS_ACCESS_KEY_ID --aws-secret-access-key=env://AWS_SECRET_ACCESS_KEY --cluster-name ${{ vars.CLUSTER_NAME }}
4547
cloud-token: ${{ secrets.DAGGER_CLOUD_TOKEN }}

.github/workflows/deploy.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ jobs:
5050

5151
- name: Build and push Docker image
5252
env:
53-
IMAGE_TAG: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com/parisjug-dagger-demo/translate-api:${{ env.TAG_VERSION }}
53+
IMAGE_TAG: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ vars.AWS_REGION }}.amazonaws.com/${{ vars.REPO_NAME }}:${{ env.TAG_VERSION }}
5454
run: |
5555
docker build -f src/main/docker/Dockerfile.jvm --platform linux/amd64,linux/arm64 -t $IMAGE_TAG .
5656
docker push $IMAGE_TAG
5757
5858
- name: update kube config
5959
run: |
60-
aws eks --region ${{ secrets.AWS_REGION }} update-kubeconfig --name ${{ vars.CLUSTER_NAME }}
60+
aws eks --region ${{ vars.AWS_REGION }} update-kubeconfig --name ${{ vars.CLUSTER_NAME }}
6161
6262
- name: deploy application to EKS
6363
env:
64-
IMAGE_TAG: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com/parisjug-dagger-demo/translate-api:${{ env.TAG_VERSION }}
64+
IMAGE_TAG: ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ vars.AWS_REGION }}.amazonaws.com/${{ vars.REPO_NAME }}:${{ env.TAG_VERSION }}
6565
run: |
6666
envsubst < src/main/kube/app.yaml | kubectl apply -f -
6767
6868
- name: Logout from Amazon ECR
69-
run: docker logout ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com
69+
run: docker logout ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.${{ vars.AWS_REGION }}.amazonaws.com
Lines changed: 79 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
package io.dagger.modules.ci;
22

33
import static io.dagger.client.Dagger.dag;
4-
import static io.dagger.modules.ci.Utils.*;
54

6-
import io.dagger.client.AwsCli;
75
import io.dagger.client.CacheVolume;
6+
import io.dagger.client.Client.AwsCliArguments;
87
import io.dagger.client.Container;
9-
import io.dagger.client.Container.PublishArguments;
108
import io.dagger.client.DaggerQueryException;
119
import io.dagger.client.Directory;
1210
import io.dagger.client.Directory.DockerBuildArguments;
@@ -27,120 +25,134 @@ public class Ci {
2725

2826
static final Logger LOG = LoggerFactory.getLogger(Ci.class);
2927

30-
private static final List<String> ARCHS = List.of("amd64", "arm64");
31-
32-
/** Build and test the application */
28+
/**
29+
* Build and test the application
30+
*
31+
* @param source the project source directory. Default is the current directory
32+
* @param skipTests whether to skip tests or not
33+
*/
3334
@Function
34-
public Container build(@DefaultPath(".") Directory source, @Default("false") boolean skipTests)
35-
throws ExecutionException, DaggerQueryException, InterruptedException {
36-
return buildEnv(source)
35+
public Container buildAndTest(@DefaultPath(".") Directory source, @Default("false") boolean skipTests) {
36+
CacheVolume mavenCache = dag().cacheVolume("m2");
37+
return dag()
38+
.container()
39+
.from("maven:3-eclipse-temurin-21")
40+
.withDirectory("/src", source)
41+
.withWorkdir("/src")
42+
.withMountedCache("/root/.m2/", mavenCache)
3743
.withExec(List.of("mvn", "-B", "clean", "package", "-DskipTests=%s".formatted(skipTests)));
3844
}
3945

46+
private Secret ecrToken(Secret awsAccessKeyId, Secret awsSecretAccessKey, String region) {
47+
return dag().awsCli()
48+
.withRegion(region)
49+
.withStaticCredentials(awsAccessKeyId, awsSecretAccessKey)
50+
.ecr().getLoginPassword();
51+
}
52+
53+
private Container buildImage(Directory source, Platform platform) {
54+
Container ctr = buildAndTest(source, true);
55+
return ctr.directory(".")
56+
.dockerBuild(new DockerBuildArguments()
57+
.withPlatform(platform)
58+
.withDockerfile("src/main/docker/Dockerfile.jvm"));
59+
}
60+
61+
private String address(Directory source, String account, String region, String repoName)
62+
throws ExecutionException, DaggerQueryException, InterruptedException {
63+
String hash = dag().gitInfo(source).commitHash().substring(0,8);
64+
return "%s.dkr.ecr.%s.amazonaws.com/%s:%s".formatted(account, region, repoName, hash);
65+
}
66+
4067
/**
4168
* Builds the application and create a Docker image
4269
*/
43-
@Function
44-
public Container buildImage(@DefaultPath(".") Directory source)
45-
throws ExecutionException, DaggerQueryException, InterruptedException {
46-
Container ctr = build(source, true);
47-
return ctr.directory(".")
70+
// @Function
71+
public Container buildImage(@DefaultPath(".") Directory source) {
72+
return buildAndTest(source, true)
73+
.directory(".")
4874
.dockerBuild(new DockerBuildArguments()
4975
.withDockerfile("src/main/docker/Dockerfile.jvm"));
5076
}
5177

5278
/**
53-
* Build a list of Docker images for multiple architectures
54-
* @param source the source directory
79+
* Pushes a Docker image to ECR
80+
*
81+
* @param image the Docker image to push
82+
* @param address the ECR image address of the form <account_id>.dkr.ecr.<region>.amazonaws.com/<repository>:<tag>
83+
* @param token the ECR authentication token
84+
*
85+
* @return the image address
5586
*/
56-
private List<Container> buildImageMultiarch(Directory source, List<String> variants) {
57-
List<Container> images = variants.stream().map(platform -> {
58-
try {
59-
LOG.info("Building image for {}", platform);
60-
return buildImage(source, platform);
61-
} catch (ExecutionException | DaggerQueryException | InterruptedException e) {
62-
throw new RuntimeException(e);
63-
}
64-
}).toList();
65-
return images;
66-
};
67-
68-
private Container buildImage(Directory source, String platform)
87+
private String pushImage(Container image, String address, Secret token)
6988
throws ExecutionException, DaggerQueryException, InterruptedException {
70-
Container ctr = build(source, true);
71-
return ctr.directory(".")
72-
.dockerBuild(new DockerBuildArguments()
73-
.withPlatform(Platform.from(platform))
74-
.withDockerfile("src/main/docker/Dockerfile.jvm"));
89+
return image
90+
.withRegistryAuth(address, "AWS", token)
91+
.publish(address);
7592
}
7693

7794
/**
78-
* Publishes the Docker image to ECR
95+
* Builds and publishes the Docker image to ECR
7996
*
8097
* @param source the source directory
8198
* @param awsAccessKeyId the AWS access key ID
8299
* @param awsSecretAccessKey the AWS secret access key
100+
* @param accountId the AWS account ID
83101
* @param region the AWS region
84102
*/
85103
@Function
86-
public String publish(@DefaultPath(".") Directory source, Secret awsAccessKeyId,
87-
Secret awsSecretAccessKey, @Default("eu-west-1") String region)
104+
public String buildAndPushImage(@DefaultPath(".") Directory source, String repoName, Secret awsAccessKeyId, Secret awsSecretAccessKey, String accountId, @Default("eu-west-1") String region)
88105
throws ExecutionException, DaggerQueryException, InterruptedException {
89-
AwsCli awsCli = aws(region, awsAccessKeyId, awsSecretAccessKey);
90-
Secret token = awsCli.ecr().getLoginPassword();
91-
String accountId = awsCli.sts().getCallerIdentity().account();
92-
String address = "%s.dkr.ecr.%s.amazonaws.com/parisjug-dagger-demo/translate-api:%s"
93-
.formatted(accountId, region, dag().gitInfo(source).commitHash().substring(0, 8));
94-
dag().container()
95-
.withRegistryAuth(address, "AWS", token)
96-
.publish(address, new PublishArguments()
97-
.withPlatformVariants(buildImageMultiarch(source, ARCHS)));
98-
return address;
106+
Container image = buildImage(source, Platform.from("amd64"));
107+
String address = address(source, accountId, region, repoName);
108+
Secret token = ecrToken(awsAccessKeyId, awsSecretAccessKey, region);
109+
return pushImage(image, address, token);
110+
}
111+
112+
private Container kubectl(String clusterName, Secret awsAccessKeyId, Secret awsSecretAccessKey, String region) {
113+
Container customCtr = dag().container().from("alpine")
114+
.withExec(List.of("apk", "add", "aws-cli", "kubectl"));
115+
List<String> cmd = List.of("eks", "update-kubeconfig", "--name", clusterName);
116+
return dag().awsCli(new AwsCliArguments().withContainer(customCtr))
117+
.withRegion(region)
118+
.withStaticCredentials(awsAccessKeyId, awsSecretAccessKey)
119+
.exec(cmd);
99120
}
100121

101122
/**
102123
* Deploys the application to EKS
103124
*
104-
* @param source the source directory
105-
* @param image the image address to deploy
106-
* @param clusterName the name of the EKS cluster
107-
* @param awsAccessKeyId the AWS access key ID
125+
* @param source the source directory
126+
* @param image the image address to deploy
127+
* @param clusterName the name of the EKS cluster
128+
* @param awsAccessKeyId the AWS access key ID
108129
* @param awsSecretAccessKey the AWS secret access key
109-
* @param region the AWS region
130+
* @param region the AWS region
110131
*/
111132
@Function
112133
public String deploy(@DefaultPath(".") Directory source, String image, String clusterName,
113134
Secret awsAccessKeyId, Secret awsSecretAccessKey, @Default("eu-west-1") String region)
114135
throws ExecutionException, DaggerQueryException, InterruptedException {
115-
String appYaml = envsubst(source.file("src/main/kube/app.yaml").contents(), "IMAGE_TAG", image);
116-
return kubectl(clusterName, region, awsAccessKeyId, awsSecretAccessKey)
136+
String appYaml = source.file("src/main/kube/app.yaml").contents().replace("${IMAGE_TAG}", image);
137+
return kubectl(clusterName, awsAccessKeyId, awsSecretAccessKey, region)
117138
.withNewFile("/tmp/app.yaml", appYaml)
118139
.withExec(List.of("kubectl", "apply", "-f", "/tmp/app.yaml"))
119140
.stdout();
120141
}
121142

122143
/**
123144
* Returns the ingress address of the application
145+
*
124146
* @return the ingress address
125147
*/
126148
@Function
127149
public String getIngress(String clusterName, Secret awsAccessKeyId, Secret awsSecretAccessKey,
128150
@Default("eu-west-1") String region)
129151
throws ExecutionException, DaggerQueryException, InterruptedException {
130-
String host = kubectl(clusterName, region, awsAccessKeyId, awsSecretAccessKey)
131-
.withExec(List.of("kubectl", "-n", "devoxxfr-dagger", "get", "ingress", "-o", "jsonpath={.items[0].status.loadBalancer.ingress[0].hostname}"))
152+
String host = kubectl(clusterName, awsAccessKeyId, awsSecretAccessKey, region)
153+
.withExec(List.of("kubectl", "-n", "devoxxfr-dagger", "get", "ingress", "-o",
154+
"jsonpath={.items[0].status.loadBalancer.ingress[0].hostname}"))
132155
.stdout();
133156
return "http://%s".formatted(host);
134157
}
135-
136-
/** Build a ready-to-use development environment */
137-
private Container buildEnv(Directory source) {
138-
CacheVolume mavenCache = dag().cacheVolume("m2");
139-
return dag()
140-
.container()
141-
.from("maven:3-eclipse-temurin-21")
142-
.withDirectory("/src", source)
143-
.withMountedCache(".m2/", mavenCache)
144-
.withWorkdir("/src");
145-
}
146158
}

ci/src/main/java/io/dagger/modules/ci/Utils.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)