Kallis made 119 not out after South Africa won the toss and batted on a well-grassed pitch in the day-night match Wednesday.
The Indian bowlers and fielders, marshaled by captain Rahul Dravid, kept the South African batsmen in check for much of the innings despite Kallis' fine innings.
The home side were wobbling at 209 for seven with 26 balls left but Kallis and tailender Andre Nel put on 39 for the eighth wicket before Nel was run out for 22 off the last ball of the innings.
It was Kallis' 14th one-day international century but his first in 25 matches against India - the only major cricket nation missing from his list of hundreds.
He had been dismissed three times in the 90s against India.
Indian pace bowlers Munaf Patel, Zaheer Khan and Ajit Agarkar each took two wickets.
It was the first action in the five-match series after the first international at the Wanderers in Johannesburg was rained out Sunday.
Kallis, batting at number three, faced the ninth ball of the innings after captain Graeme Smith was leg before to Khan for one. He batted solidly from the start of his innings and made his runs off 160 balls with 15 fours.
South Africa were in some trouble at 63 for three but AB de Villiers (41) helped Kallis put on 87 for the fourth wicket.
They had to overcome some accurate slow bowling from Harbhajan Singh and Sachin Tendulkar, who conceded only a combined 29 runs in eight overs before De Villiers went on the attack against off-spinner Harbhajan.
He swept him for four, then swung him over midwicket for six, prompting Harbhajan to fire in a ball down the legside that went for five wides.
The over cost 17 runs.
De Villiers went for one ambitious shot too many when he lost his balance and was stumped attempting a reverse sweep against part-time left-arm spinner Dinesh Mongia.
Mark Boucher then helped Kallis put on 46 off 46 balls. The innings lost momentum as Boucher, Justin Kemp and Shaun Pollock were out in quick succession before Nel, with a previous highest score of 12, played a surprisingly effective hand.
South Africa opted for an all-seam bowling attack while India picked a side with seven batsmen and only four specialist bowlers, leaving out all-rounder Irfan Pathan.
They were still without opening batsman Virender Sehwag, who suffered a finger injury before the team's warm-up match in Benoni last Thursday.
Fall of wickets: 1-3, 2-47, 3-63, 4-150, 5-196, 6-209, 7-209, 8-248
Did not bat: C Langeveldt, M Ntini.
India: R Dravid, S Tendulkar, W Jaffer, M Kaif, D Mongia, S Raina, M Dhoni, Harbhajan Singh, A Agarkar, Zaheer Khan, M Patel.
Umpires: B Doctrove (WIS), I Howell (RSA).
TV umpire: B Jerling (RSA)
Match referee: C Broad (ENG)