Skip to content

Commit cdadaea

Browse files
authored
Merge pull request #117 from code0-tech/109-container-orchestrator
Create orchestrator for system dependencies
2 parents 7d4d6a6 + 413e16d commit cdadaea

13 files changed

Lines changed: 487 additions & 7 deletions

File tree

.gitlab-ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ boot:docker:
140140
-e SAGITTARIUS_DATABASE_PORT=5432
141141
-e SAGITTARIUS_REDIS_HOST=redis
142142
-e SAGITTARIUS_REDIS_PORT=6379
143+
-e SAGITTARIUS_DISABLE_ORCHESTRATOR=true
143144
-e RAILS_ENV=production
144145
ghcr.io/code0-tech/sagittarius/ci-builds:${CI_COMMIT_SHA} &
145146
- >
@@ -154,3 +155,33 @@ boot:docker:
154155
--retry-delay 3
155156
--retry-connrefused
156157
http://sagittarius:3000/health/liveness
158+
159+
boot:docker-orchestrated:
160+
stage: test
161+
image: docker:26.0.0-dind
162+
variables:
163+
DOCKER_HOST: unix:///var/run/docker.sock
164+
script:
165+
- /usr/local/bin/dockerd-entrypoint.sh &
166+
- sleep 20
167+
- docker network create sagittarius_default
168+
- >
169+
docker run
170+
--name sagittarius
171+
--network sagittarius_default
172+
--network-alias sagittarius
173+
-e RAILS_ENV=production
174+
-v /var/run/docker.sock:/var/run/docker.sock
175+
ghcr.io/code0-tech/sagittarius/ci-builds:${CI_COMMIT_SHA} &
176+
- >
177+
docker run
178+
--rm
179+
--network sagittarius_default
180+
curlimages/curl:8.5.0
181+
curl
182+
--fail
183+
-sv
184+
--retry 20
185+
--retry-delay 3
186+
--retry-connrefused
187+
http://sagittarius:3000/health/liveness

.rubocop.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ Lint/AmbiguousBlockAssociation:
1717
Metrics/AbcSize:
1818
Enabled: false
1919

20+
Metrics/BlockLength:
21+
Exclude:
22+
- lib/tasks/**/*
23+
2024
Metrics/MethodLength:
2125
Enabled: false
2226

Dockerfile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ RUN apt-get update -qq && \
5656
COPY --from=build /usr/local/bundle /usr/local/bundle
5757
COPY --from=build /rails /rails
5858

59-
# Run and own only the runtime files as a non-root user for security
60-
RUN useradd rails --create-home --shell /bin/bash && \
61-
chown -R rails:rails db log storage tmp
62-
USER rails:rails
63-
6459
# Entrypoint prepares the database.
6560
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
6661

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,5 @@ gem 'sidekiq', '~> 7.1'
7474
gem 'lograge', '~> 0.14.0'
7575

7676
gem 'declarative_policy', '~> 1.1'
77+
78+
gem 'docker-api', '~> 2.2'

Gemfile.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ GEM
102102
declarative_policy (1.1.0)
103103
diff-lcs (1.5.1)
104104
docile (1.4.0)
105+
docker-api (2.2.0)
106+
excon (>= 0.47.0)
107+
multi_json
105108
drb (2.2.1)
106109
erubi (1.12.0)
107110
escape_utils (1.3.0)
111+
excon (0.110.0)
108112
extended-markdown-filter (0.7.0)
109113
html-pipeline (~> 2.9)
110114
factory_bot (6.4.5)
@@ -153,6 +157,7 @@ GEM
153157
mini_mime (1.1.5)
154158
minitest (5.22.3)
155159
msgpack (1.7.2)
160+
multi_json (1.15.0)
156161
mutex_m (0.2.0)
157162
net-imap (0.4.10)
158163
date
@@ -336,6 +341,7 @@ DEPENDENCIES
336341
database_cleaner-active_record (~> 2.1)
337342
debug
338343
declarative_policy (~> 1.1)
344+
docker-api (~> 2.2)
339345
factory_bot_rails (~> 6.2)
340346
graphql (~> 2.1)
341347
graphql-docs (~> 4.0)

bin/docker-entrypoint

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
11
#!/bin/bash -e
22

3-
# If running the rails server then create or migrate existing database
43
if [ "${1}" == "./bin/rails" ] && [ "${2}" == "server" ]; then
4+
if [ "${SAGITTARIUS_DISABLE_ORCHESTRATOR}" != "true" ]; then
5+
# orchestrate dependencies
6+
bundle exec rake \
7+
orchestrator:start[postgresql] \
8+
orchestrator:start[redis] \
9+
orchestrator:await_healthy[postgresql,5] \
10+
orchestrator:await_healthy[redis,5] \
11+
orchestrator:connect_self
12+
13+
bundle exec rake orchestrator:debug
14+
15+
# create connection environment variables
16+
eval $(bundle exec rake orchestrator:create_connection_environment[postgresql,redis])
17+
fi
18+
19+
# prepare database
520
bundle exec rake db:prepare
621
FILTER=01_application_settings bundle exec rake db:seed_fu
722
fi

config/initializers/application_settings.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Rails.application.config.to_prepare do
44
next unless Rails.env.production?
5-
next if ARGV.grep(/db:/).any?
5+
next if ARGV.grep(/db:|orchestrator:/).any?
66

77
ApplicationSetting.assert_settings_present!
88
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# frozen_string_literal: true
2+
3+
module Sagittarius
4+
module Orchestrator
5+
class Container
6+
attr_accessor :internal_container
7+
8+
def image
9+
raise NotImplementedError
10+
end
11+
12+
def name
13+
raise NotImplementedError
14+
end
15+
16+
def cmd
17+
nil
18+
end
19+
20+
def environment_variables
21+
[]
22+
end
23+
24+
def volumes
25+
[]
26+
end
27+
28+
def ports
29+
nil
30+
end
31+
32+
def healthy?
33+
return false if internal_container.nil?
34+
35+
internal_container.refresh!
36+
internal_container.info['State']['Status'] == 'running'
37+
end
38+
39+
def self.[](container)
40+
Containers.const_get(container.capitalize).new
41+
end
42+
end
43+
end
44+
end
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# frozen_string_literal: true
2+
3+
module Sagittarius
4+
module Orchestrator
5+
module Containers
6+
class Postgresql < Container
7+
def image
8+
'postgres:16.1'
9+
end
10+
11+
def name
12+
'postgresql'
13+
end
14+
15+
def environment_variables
16+
config = ActiveRecord::Base.connection_db_config.configuration_hash
17+
18+
%W[
19+
POSTGRES_USER=#{config[:username]}
20+
POSTGRES_PASSWORD=#{config[:password]}
21+
POSTGRES_DB=#{config[:database]}
22+
]
23+
end
24+
25+
def volumes
26+
{
27+
data: '/var/lib/postgresql/data/',
28+
}
29+
end
30+
31+
def ports
32+
{
33+
'5432/tcp' => [{ 'HostIp' => '127.0.0.1', 'HostPort' => '5433' }],
34+
}
35+
end
36+
37+
def healthy?
38+
# exec returns [[stdout], [], exit_code]
39+
super && internal_container.exec(%w[pg_isready]).last.zero?
40+
end
41+
42+
def orchestrator_connection_details
43+
return {} unless healthy?
44+
45+
{
46+
SAGITTARIUS_DATABASE_HOST: internal_container.info['Name'].delete_prefix('/'),
47+
SAGITTARIUS_DATABASE_PORT: 5432,
48+
}
49+
end
50+
end
51+
end
52+
end
53+
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
module Sagittarius
4+
module Orchestrator
5+
module Containers
6+
class Redis < Container
7+
def image
8+
'redis:7.2.3-alpine'
9+
end
10+
11+
def name
12+
'redis'
13+
end
14+
15+
def cmd
16+
%w[redis-server --save 1 1 --loglevel warning]
17+
end
18+
19+
def volumes
20+
{
21+
data: '/data',
22+
}
23+
end
24+
25+
def ports
26+
{
27+
'6379/tcp' => [{ 'HostIp' => '127.0.0.1', 'HostPort' => '6380' }],
28+
}
29+
end
30+
31+
def orchestrator_connection_details
32+
return {} unless healthy?
33+
34+
{
35+
SAGITTARIUS_REDIS_HOST: internal_container.info['Name'].delete_prefix('/'),
36+
SAGITTARIUS_REDIS_PORT: 6379,
37+
}
38+
end
39+
end
40+
end
41+
end
42+
end

0 commit comments

Comments
 (0)